tests/test.sh exit code (0 → resolved); the classification below is post-hoc and cannot change it.Inspect /app directory and seeder
ls /app/ && cat /app/setup.sh 2>/dev/null | head -100
setup.sh
starter
#!/bin/bash
[redacted: decontamination sentinel]
[redacted: decontamination sentinel]
#
# Pre-seeds the consumer Lambda + its role with a broken-by-design
# handler and incomplete IAM. The agent has to build everything else
# (queues, DDB, apigw, integration, deployment, ESM) AND fix this
# Lambda's handler + role. Without the pre-seeded Lambda, Opus 4.7
# tends to read the prose and forget the consumer path entirely.
set -euo pipefail
REGION="${AWS_DEFAULT_REGION:-us-east-1}"
ACCOUNT_ID="000000000000"
LAMBDA_FUNC="orders-consumer"
LAMBDA_ROLE="orders-consumer-role"
log() { echo "[setup] $*" >&2; }
log "waiting for localstack"
for _ in $(seq 1 80); do
HEALTH=$(curl -sf http://localstack:4566/_localstack/health || true)
echo "$HEALTH" | grep -qE '"lambda": "(available|running)"' \
&& echo "$HEALTH" | grep -qE '"iam": "(available|running)"' \
&& break
sleep 2
done
log "creating Lambda consumer role (deliberately incomplete)"
TRUST=$(cat <<'JSON'
{
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}
]
}
JSON
)
aws iam create-role \
--role-name "$LAMBDA_ROLE" \
--assume-role-policy-document "$TRUST" >/dev/null
aws iam attach-role-policy \
--role-name "$LAMBDA_ROLE" \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# Note: no dynamodb:PutItem, no sqs perms. Agent fixes this.
ROLE_ARN=$(aws iam get-role --role-name "$LAMBDA_ROLE" --query 'Role.Arn' --output text)
log "packaging Lambda (broken-by-design inline handler)"
WORKDIR="$(mktemp -d)"
cat > "${WORKDIR}/handler.py" <<'PY'
"""Orders consumer - broken by design.
Known issues (agent must fix):
- Not idempotent: a duplicate message will try to PutItem again,
which will either overwrite (wrong) or fail (wrong shape).
- Returns a per-record 'failed' list instead of the AWS-required
batchItemFailures shape for partial-batch-failure reporting.
"""
import json
import os
import time
import boto3
_endpoint = os.environ.get("AWS_ENDPOINT_URL", "http://localstack:4566")
ddb = boto3.client("dynamodb", endpoint_url=_endpoint)
TABLE_NAME = os.environ.get("TABLE_NAME", "orders")
def _process_record(record):
payload = json.loads(record["body"])
order_id = payload["order_id"]
merchant_id = payload["merchant_id"]
amount = int(payload["amount"])
ddb.put_item(
TableName=TABLE_NAME,
Item={
"order_id": {"S": order_id},
"merchant_id": {"S": merchant_id},
"amount": {"N": str(amount)},
"created_at": {"N": str(int(time.time()))},
},
)
def lambda_handler(event, context):
failed = []
for record in event.get("Records", []):
try:
_process_record(record)
except Exception as e:
print(f"[error] msgId={record.get('messageId')} {type(e).__name__}: {e}")
failed.append({"itemIdentifier": record["messageId"]})
return {"failed": failed}
PY
(cd "$WORKDIR" && zip -q handler.zip handler.py)
[stdout]
setup.sh
starter
#!/bin/bash
[redacted: decontamination sentinel]
[redacted: decontamination sentinel]
#
# Pre-seeds the consumer Lambda + its role with a broken-by-design
# handler and incomplete IAM. The agent has to build everything else
# (queues, DDB, apigw, integration, deployment, ESM) AND fix this
# Lambda's handler + role. Without the pre-seeded Lambda, Opus 4.7
# tends to read the prose and forget the consumer path entirely.
set -euo pipefail
REGION="${AWS_DEFAULT_REGION:-us-east-1}"
ACCOUNT_ID="000000000000"
LAMBDA_FUNC="orders-consumer"
LAMBDA_ROLE="orders-consumer-role"
log() { echo "[setup] $*" >&2; }
log "waiting for localstack"
for _ in $(seq 1 80); do
HEALTH=$(curl -sf http://localstack:4566/_localstack/health || true)
echo "$HEALTH" | grep -qE '"lambda": "(available|running)"' \
&& echo "$HEALTH" | grep -qE '"iam": "(available|running)"' \
&& break
sleep 2
done
log "creating Lambda consumer role (deliberately incomplete)"
TRUST=$(cat <<'JSON'
{
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}
]
}
JSON
)
aws iam create-role \
--role-name "$LAMBDA_ROLE" \
--assume-role-policy-document "$TRUST" >/dev/null
aws iam attach-role-policy \
--role-name "$LAMBDA_ROLE" \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# Note: no dynamodb:PutItem, no sqs perms. Agent fixes this.
ROLE_ARN=$(aws iam get-role --role-name "$LAMBDA_ROLE" --query 'Role.Arn' --output text)
log "packaging Lambda (broken-by-design inline handler)"
WORKDIR="$(mktemp -d)"
cat > "${WORKDIR}/handler.py" <<'PY'
"""Orders consumer - broken by design.
Known issues (agent must fix):
- Not idempotent: a duplicate message will try to PutItem again,
which will either overwrite (wrong) or fail (wrong shape).
- Returns a per-record 'failed' list instead of the AWS-required
batchItemFailures shape for partial-batch-failure reporting.
"""
import json
import os
import time
import boto3
_endpoint = os.environ.get("AWS_ENDPOINT_URL", "http://localstack:4566")
ddb = boto3.client("dynamodb", endpoint_url=_endpoint)
TABLE_NAME = os.environ.get("TABLE_NAME", "orders")
def _process_record(record):
payload = json.loads(record["body"])
order_id = payload["order_id"]
merchant_id = payload["merchant_id"]
amount = int(payload["amount"])
ddb.put_item(
TableName=TABLE_NAME,
Item={
"order_id": {"S": order_id},
"merchant_id": {"S": merchant_id},
"amount": {"N": str(amount)},
"created_at": {"N": str(int(time.time()))},
},
)
def lambda_handler(event, context):
failed = []
for record in event.get("Records", []):
try:
_process_record(record)
except Exception as e:
print(f"[error] msgId={record.get('messageId')} {type(e).__name__}: {e}")
failed.append({"itemIdentifier": record["messageId"]})
return {"failed": failed}
PY
(cd "$WORKDIR" && zip -q handler.zip handler.py)Read rest of setup script
cat /app/setup.sh | tail -60
import os
import time
import boto3
_endpoint = os.environ.get("AWS_ENDPOINT_URL", "http://localstack:4566")
ddb = boto3.client("dynamodb", endpoint_url=_endpoint)
TABLE_NAME = os.environ.get("TABLE_NAME", "orders")
def _process_record(record):
payload = json.loads(record["body"])
order_id = payload["order_id"]
merchant_id = payload["merchant_id"]
amount = int(payload["amount"])
ddb.put_item(
TableName=TABLE_NAME,
Item={
"order_id": {"S": order_id},
"merchant_id": {"S": merchant_id},
"amount": {"N": str(amount)},
"created_at": {"N": str(int(time.time()))},
},
)
def lambda_handler(event, context):
failed = []
for record in event.get("Records", []):
try:
_process_record(record)
except Exception as e:
print(f"[error] msgId={record.get('messageId')} {type(e).__name__}: {e}")
failed.append({"itemIdentifier": record["messageId"]})
return {"failed": failed}
PY
(cd "$WORKDIR" && zip -q handler.zip handler.py)
log "creating Lambda function"
aws lambda create-function \
--function-name "$LAMBDA_FUNC" \
--runtime python3.11 \
--role "$ROLE_ARN" \
--handler handler.lambda_handler \
--timeout 30 \
--memory-size 512 \
--environment "Variables={AWS_ENDPOINT_URL=http://localstack:4566,TABLE_NAME=orders}" \
--zip-file "fileb://${WORKDIR}/handler.zip" >/dev/null
for _ in $(seq 1 30); do
STATE=$(aws lambda get-function --function-name "$LAMBDA_FUNC" \
--query 'Configuration.State' --output text 2>/dev/null || echo "Pending")
[ "$STATE" = "Active" ] && break
sleep 1
done
log "Lambda $LAMBDA_FUNC ready"
log "done"
[stdout]
import os
import time
import boto3
_endpoint = os.environ.get("AWS_ENDPOINT_URL", "http://localstack:4566")
ddb = boto3.client("dynamodb", endpoint_url=_endpoint)
TABLE_NAME = os.environ.get("TABLE_NAME", "orders")
def _process_record(record):
payload = json.loads(record["body"])
order_id = payload["order_id"]
merchant_id = payload["merchant_id"]
amount = int(payload["amount"])
ddb.put_item(
TableName=TABLE_NAME,
Item={
"order_id": {"S": order_id},
"merchant_id": {"S": merchant_id},
"amount": {"N": str(amount)},
"created_at": {"N": str(int(time.time()))},
},
)
def lambda_handler(event, context):
failed = []
for record in event.get("Records", []):
try:
_process_record(record)
except Exception as e:
print(f"[error] msgId={record.get('messageId')} {type(e).__name__}: {e}")
failed.append({"itemIdentifier": record["messageId"]})
return {"failed": failed}
PY
(cd "$WORKDIR" && zip -q handler.zip handler.py)
log "creating Lambda function"
aws lambda create-function \
--function-name "$LAMBDA_FUNC" \
--runtime python3.11 \
--role "$ROLE_ARN" \
--handler handler.lambda_handler \
--timeout 30 \
--memory-size 512 \
--environment "Variables={AWS_ENDPOINT_URL=http://localstack:4566,TABLE_NAME=orders}" \
--zip-file "fileb://${WORKDIR}/handler.zip" >/dev/null
for _ in $(seq 1 30); do
STATE=$(aws lambda get-function --function-name "$LAMBDA_FUNC" \
--query 'Configuration.State' --output text 2>/dev/null || echo "Pending")
[ "$STATE" = "Active" ] && break
sleep 1
done
log "Lambda $LAMBDA_FUNC ready"
log "done"Inspect starter directory
ls /app/starter/ && cat /app/starter/* 2>/dev/null
setup.sh
#!/bin/bash
[redacted: decontamination sentinel]
[redacted: decontamination sentinel]
#
# Pre-seeds the consumer Lambda + its role with a broken-by-design
# handler and incomplete IAM. The agent has to build everything else
# (queues, DDB, apigw, integration, deployment, ESM) AND fix this
# Lambda's handler + role. Without the pre-seeded Lambda, Opus 4.7
# tends to read the prose and forget the consumer path entirely.
set -euo pipefail
REGION="${AWS_DEFAULT_REGION:-us-east-1}"
ACCOUNT_ID="000000000000"
LAMBDA_FUNC="orders-consumer"
LAMBDA_ROLE="orders-consumer-role"
log() { echo "[setup] $*" >&2; }
log "waiting for localstack"
for _ in $(seq 1 80); do
HEALTH=$(curl -sf http://localstack:4566/_localstack/health || true)
echo "$HEALTH" | grep -qE '"lambda": "(available|running)"' \
&& echo "$HEALTH" | grep -qE '"iam": "(available|running)"' \
&& break
sleep 2
done
log "creating Lambda consumer role (deliberately incomplete)"
TRUST=$(cat <<'JSON'
{
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}
]
}
JSON
)
aws iam create-role \
--role-name "$LAMBDA_ROLE" \
--assume-role-policy-document "$TRUST" >/dev/null
aws iam attach-role-policy \
--role-name "$LAMBDA_ROLE" \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# Note: no dynamodb:PutItem, no sqs perms. Agent fixes this.
ROLE_ARN=$(aws iam get-role --role-name "$LAMBDA_ROLE" --query 'Role.Arn' --output text)
log "packaging Lambda (broken-by-design inline handler)"
WORKDIR="$(mktemp -d)"
cat > "${WORKDIR}/handler.py" <<'PY'
"""Orders consumer - broken by design.
Known issues (agent must fix):
- Not idempotent: a duplicate message will try to PutItem again,
which will either overwrite (wrong) or fail (wrong shape).
- Returns a per-record 'failed' list instead of the AWS-required
batchItemFailures shape for partial-batch-failure reporting.
"""
import json
import os
import time
import boto3
_endpoint = os.environ.get("AWS_ENDPOINT_URL", "http://localstack:4566")
ddb = boto3.client("dynamodb", endpoint_url=_endpoint)
TABLE_NAME = os.environ.get("TABLE_NAME", "orders")
def _process_record(record):
payload = json.loads(record["body"])
order_id = payload["order_id"]
merchant_id = payload["merchant_id"]
amount = int(payload["amount"])
ddb.put_item(
TableName=TABLE_NAME,
Item={
"order_id": {"S": order_id},
"merchant_id": {"S": merchant_id},
"amount": {"N": str(amount)},
"created_at": {"N": str(int(time.time()))},
},
)
def lambda_handler(event, context):
failed = []
for record in event.get("Records", []):
try:
_process_record(record)
except Exception as e:
print(f"[error] msgId={record.get('messageId')} {type(e).__name__}: {e}")
failed.append({"itemIdentifier": record["messageId"]})
return {"failed": failed}
PY
(cd "$WORKDIR" && zip -q handler.zip handler.py)
log "creating Lambda function"
aws lambda create-function \
--function-name "$LAMBDA_FUNC" \
--runtime python3.11 \
--role "$ROLE_ARN" \
--handler handler.lambda_handler \
--timeout 30 \
--memory-size 512 \
--environment "Variables={AWS_ENDPOINT_URL=http://localstack:4566,TABLE_NAME=orders}" \
--zip-file "fileb://${WORKDIR}/handler.zip" >/dev/null
for _ in $(seq 1 30); do
STATE=$(aws lambda get-function --function-name "$LAMBDA_FUNC" \
--query 'Configuration.State' --output text 2>/dev/null || echo "Pending")
[ "$STATE" = "Active" ] && break
sleep 1
done
log "Lambda $LAMBDA_FUNC ready"
log "done"
[stdout]
setup.sh
#!/bin/bash
[redacted: decontamination sentinel]
[redacted: decontamination sentinel]
#
# Pre-seeds the consumer Lambda + its role with a broken-by-design
# handler and incomplete IAM. The agent has to build everything else
# (queues, DDB, apigw, integration, deployment, ESM) AND fix this
# Lambda's handler + role. Without the pre-seeded Lambda, Opus 4.7
# tends to read the prose and forget the consumer path entirely.
set -euo pipefail
REGION="${AWS_DEFAULT_REGION:-us-east-1}"
ACCOUNT_ID="000000000000"
LAMBDA_FUNC="orders-consumer"
LAMBDA_ROLE="orders-consumer-role"
log() { echo "[setup] $*" >&2; }
log "waiting for localstack"
for _ in $(seq 1 80); do
HEALTH=$(curl -sf http://localstack:4566/_localstack/health || true)
echo "$HEALTH" | grep -qE '"lambda": "(available|running)"' \
&& echo "$HEALTH" | grep -qE '"iam": "(available|running)"' \
&& break
sleep 2
done
log "creating Lambda consumer role (deliberately incomplete)"
TRUST=$(cat <<'JSON'
{
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}
]
}
JSON
)
aws iam create-role \
--role-name "$LAMBDA_ROLE" \
--assume-role-policy-document "$TRUST" >/dev/null
aws iam attach-role-policy \
--role-name "$LAMBDA_ROLE" \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# Note: no dynamodb:PutItem, no sqs perms. Agent fixes this.
ROLE_ARN=$(aws iam get-role --role-name "$LAMBDA_ROLE" --query 'Role.Arn' --output text)
log "packaging Lambda (broken-by-design inline handler)"
WORKDIR="$(mktemp -d)"
cat > "${WORKDIR}/handler.py" <<'PY'
"""Orders consumer - broken by design.
Known issues (agent must fix):
- Not idempotent: a duplicate message will try to PutItem again,
which will either overwrite (wrong) or fail (wrong shape).
- Returns a per-record 'failed' list instead of the AWS-required
batchItemFailures shape for partial-batch-failure reporting.
"""
import json
import os
import time
import boto3
_endpoint = os.environ.get("AWS_ENDPOINT_URL", "http://localstack:4566")
ddb = boto3.client("dynamodb", endpoint_url=_endpoint)
TABLE_NAME = os.environ.get("TABLE_NAME", "orders")
def _process_record(record):
payload = json.loads(record["body"])
order_id = payload["order_id"]
merchant_id = payload["merchant_id"]
amount = int(payload["amount"])
ddb.put_item(
TableName=TABLE_NAME,
Item={
"order_id": {"S": order_id},
"merchant_id": {"S": merchant_id},
"amount": {"N": str(amount)},
"created_at": {"N": str(int(time.time()))},
},
)
def lambda_handler(event, context):
failed = []
for record in event.get("Records", []):
try:
_process_record(record)
except Exception as e:
print(f"[error] msgId={record.get('messageId')} {type(e).__name__}: {e}")
failed.append({"itemIdentifier": record["messageId"]})
return {"failed": failed}
PY
(cd "$WORKDIR" && zip -q handler.zip handler.py)
log "creating Lambda function"
aws lambda create-function \
--function-name "$LAMBDA_FUNC" \
--runtime python3.11 \
--role "$ROLE_ARN" \
--handler handler.lambda_handler \
--timeout 30 \
--memory-size 512 \
--environment "Variables={AWS_ENDPOINT_URL=http://localstack:4566,TABLE_NAME=orders}" \
--zip-file "fileb://${WORKDIR}/handler.zip" >/dev/null
for _ in $(seq 1 30); do
STATE=$(aws lambda get-function --function-name "$LAMBDA_FUNC" \
--query 'Configuration.State' --output text 2>/dev/null || echo "Pending")
[ "$STATE" = "Active" ] && break
sleep 1
done
log "Lambda $LAMBDA_FUNC ready"
log "done"Check pre-created Lambda and role
aws --endpoint-url=http://localstack:4566 lambda get-function --function-name orders-consumer --query 'Configuration.[FunctionName,State,Role]' --output text 2>&1; echo "---"; aws --endpoint-url=http://localstack:4566 iam list-attached-role-policies --role-name orders-consumer-role 2>&1; echo "---"; aws --endpoint-url=http://localstack:4566 iam list-role-policies --role-name orders-consumer-role 2>&1
orders-consumer Active arn:aws:iam::000000000000:role/orders-consumer-role
---
{
"AttachedPolicies": [
{
"PolicyName": "AWSLambdaBasicExecutionRole",
"PolicyArn": "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
]
}
---
{
"PolicyNames": []
}
[stdout]
orders-consumer Active arn:aws:iam::000000000000:role/orders-consumer-role
---
{
"AttachedPolicies": [
{
"PolicyName": "AWSLambdaBasicExecutionRole",
"PolicyArn": "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
]
}
---
{
"PolicyNames": []
}Check AWS env and identity
echo "AWS env:"; env | grep -i aws; echo "---"; aws --endpoint-url=http://localstack:4566 sts get-caller-identity 2>&1
AWS env:
AWS_DEFAULT_REGION=us-east-1
AWS_PAGER=
AWS_SECRET_ACCESS_KEY=test
AWS_ACCESS_KEY_ID=test
AWS_ENDPOINT_URL=http://localstack:4566
---
{
"UserId": "AKIAIOSFODNN7EXAMPLE",
"Account": "000000000000",
"Arn": "arn:aws:iam::000000000000:root"
}
[stdout]
AWS env:
AWS_DEFAULT_REGION=us-east-1
AWS_PAGER=
AWS_SECRET_ACCESS_KEY=test
AWS_ACCESS_KEY_ID=test
AWS_ENDPOINT_URL=http://localstack:4566
---
{
"UserId": "AKIAIOSFODNN7EXAMPLE",
"Account": "000000000000",
"Arn": "arn:aws:iam::000000000000:root"
}Create DDB table and FIFO queues
mkdir -p /tmp/build && cd /tmp/build
ACCOUNT_ID=000000000000
REGION=us-east-1
# 1. DDB table
aws dynamodb create-table \
--table-name orders \
--attribute-definitions AttributeName=order_id,AttributeType=S \
--key-schema AttributeName=order_id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST 2>&1 | tail -3
echo "---ddb done---"
# 2. DLQ first (FIFO)
DLQ_URL=$(aws sqs create-queue \
--queue-name orders-dlq.fifo \
--attributes 'FifoQueue=true,ContentBasedDeduplication=false' \
--query QueueUrl --output text)
echo "DLQ_URL=$DLQ_URL"
DLQ_ARN=$(aws sqs get-queue-attributes --queue-url "$DLQ_URL" --attribute-names QueueArn --query 'Attributes.QueueArn' --output text)
echo "DLQ_ARN=$DLQ_ARN"
# 3. Main queue with redrive
REDRIVE="{\"deadLetterTargetArn\":\"$DLQ_ARN\",\"maxReceiveCount\":\"5\"}"
MAIN_URL=$(aws sqs create-queue \
--queue-name orders.fifo \
--attributes "FifoQueue=true,ContentBasedDeduplication=false,RedrivePolicy=$REDRIVE,VisibilityTimeout=60" \
--query QueueUrl --output text)
echo "MAIN_URL=$MAIN_URL"
MAIN_ARN=$(aws sqs get-queue-attributes --queue-url "$MAIN_URL" --attribute-names QueueArn --query 'Attributes.QueueArn' --output text)
echo "MAIN_ARN=$MAIN_ARN""DeletionProtectionEnabled": false
}
}
---ddb done---
DLQ_URL=http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders-dlq.fifo
DLQ_ARN=arn:aws:sqs:us-east-1:000000000000:orders-dlq.fifo
aws: [ERROR]: An error occurred (ParamValidation): Error parsing parameter '--attributes': Expected: '=', received: '"' for input:
FifoQueue=true,ContentBasedDeduplication=false,RedrivePolicy={"deadLetterTargetArn":"arn:aws:sqs:us-east-1:000000000000:orders-dlq.fifo","maxReceiveCount":"5"},VisibilityTimeout=60
^
MAIN_URL=
aws: [ERROR]: An error occurred (AWS.SimpleQueueService.NonExistentQueue) when calling the GetQueueAttributes operation: The specified queue does not exist.
MAIN_ARN=
Shell cwd was reset to /app
[stdout]
"DeletionProtectionEnabled": false
}
}
---ddb done---
DLQ_URL=http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders-dlq.fifo
DLQ_ARN=arn:aws:sqs:us-east-1:000000000000:orders-dlq.fifo
aws: [ERROR]: An error occurred (ParamValidation): Error parsing parameter '--attributes': Expected: '=', received: '"' for input:
FifoQueue=true,ContentBasedDeduplication=false,RedrivePolicy={"deadLetterTargetArn":"arn:aws:sqs:us-east-1:000000000000:orders-dlq.fifo","maxReceiveCount":"5"},VisibilityTimeout=60
^
MAIN_URL=
aws: [ERROR]: An error occurred (AWS.SimpleQueueService.NonExistentQueue) when calling the GetQueueAttributes operation: The specified queue does not exist.
MAIN_ARN=
[stderr]
Shell cwd was reset to /appCreate main FIFO queue with redrive
cd /tmp/build
DLQ_ARN="arn:aws:sqs:us-east-1:000000000000:orders-dlq.fifo"
cat > /tmp/build/main-attrs.json <<EOF
{
"FifoQueue": "true",
"ContentBasedDeduplication": "false",
"VisibilityTimeout": "60",
"RedrivePolicy": "{\"deadLetterTargetArn\":\"$DLQ_ARN\",\"maxReceiveCount\":\"5\"}"
}
EOF
cat /tmp/build/main-attrs.json
MAIN_URL=$(aws sqs create-queue \
--queue-name orders.fifo \
--attributes file:///tmp/build/main-attrs.json \
--query QueueUrl --output text)
echo "MAIN_URL=$MAIN_URL"
MAIN_ARN=$(aws sqs get-queue-attributes --queue-url "$MAIN_URL" --attribute-names QueueArn --query 'Attributes.QueueArn' --output text)
echo "MAIN_ARN=$MAIN_ARN"
aws sqs get-queue-attributes --queue-url "$MAIN_URL" --attribute-names All --query 'Attributes.RedrivePolicy' --output text{
"FifoQueue": "true",
"ContentBasedDeduplication": "false",
"VisibilityTimeout": "60",
"RedrivePolicy": "{\"deadLetterTargetArn\":\"arn:aws:sqs:us-east-1:000000000000:orders-dlq.fifo\",\"maxReceiveCount\":\"5\"}"
}
MAIN_URL=http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo
MAIN_ARN=arn:aws:sqs:us-east-1:000000000000:orders.fifo
{"deadLetterTargetArn":"arn:aws:sqs:us-east-1:000000000000:orders-dlq.fifo","maxReceiveCount":"5"}
Shell cwd was reset to /app
[stdout]
{
"FifoQueue": "true",
"ContentBasedDeduplication": "false",
"VisibilityTimeout": "60",
"RedrivePolicy": "{\"deadLetterTargetArn\":\"arn:aws:sqs:us-east-1:000000000000:orders-dlq.fifo\",\"maxReceiveCount\":\"5\"}"
}
MAIN_URL=http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo
MAIN_ARN=arn:aws:sqs:us-east-1:000000000000:orders.fifo
{"deadLetterTargetArn":"arn:aws:sqs:us-east-1:000000000000:orders-dlq.fifo","maxReceiveCount":"5"}
[stderr]
Shell cwd was reset to /appAttach inline policy to consumer role
cat > /tmp/build/consumer-policy.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:GetQueueAttributes",
"sqs:ChangeMessageVisibility"
],
"Resource": "arn:aws:sqs:us-east-1:000000000000:orders.fifo"
},
{
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:GetItem",
"dynamodb:UpdateItem",
"dynamodb:DescribeTable"
],
"Resource": "arn:aws:dynamodb:us-east-1:000000000000:table/orders"
}
]
}
EOF
aws iam put-role-policy \
--role-name orders-consumer-role \
--policy-name consumer-inline \
--policy-document file:///tmp/build/consumer-policy.json
echo "policy attached"
aws iam list-role-policies --role-name orders-consumer-rolepolicy attached
{
"PolicyNames": [
"consumer-inline"
]
}
[stdout]
policy attached
{
"PolicyNames": [
"consumer-inline"
]
}{
"query": "select:TodoWrite",
"max_results": 1
}
, output,
{"type": "tool_reference", "tool_name": "TodoWrite"}
import json
import os
import time
import boto3
from botocore.exceptions import ClientError
_endpoint = os.environ.get("AWS_ENDPOINT_URL", "http://localstack:4566")
ddb = boto3.client("dynamodb", endpoint_url=_endpoint)
TABLE_NAME = os.environ.get("TABLE_NAME", "orders")
def _process_record(record):
payload = json.loads(record["body"])
order_id = payload["order_id"]
merchant_id = payload["merchant_id"]
amount = int(payload["amount"])
try:
ddb.put_item(
TableName=TABLE_NAME,
Item={
"order_id": {"S": order_id},
"merchant_id": {"S": merchant_id},
"amount": {"N": str(amount)},
"created_at": {"N": str(int(time.time() * 1000))},
},
ConditionExpression="attribute_not_exists(order_id)",
)
except ClientError as e:
if e.response["Error"]["Code"] == "ConditionalCheckFailedException":
return
raise
def lambda_handler(event, context):
batch_item_failures = []
for record in event.get("Records", []):
try:
_process_record(record)
except Exception as e:
print(f"[error] msgId={record.get('messageId')} {type(e).__name__}: {e}")
batch_item_failures.append({"itemIdentifier": record["messageId"]})
return {"batchItemFailures": batch_item_failures}
Repackage and deploy fixed lambda
cd /tmp/build && rm -f handler.zip && zip -q handler.zip handler.py && ls -la handler.zip aws lambda update-function-code \ --function-name orders-consumer \ --zip-file fileb:///tmp/build/handler.zip \ --query 'LastUpdateStatus' --output text # wait for ready for _ in $(seq 1 30); do S=$(aws lambda get-function --function-name orders-consumer --query 'Configuration.LastUpdateStatus' --output text) [ "$S" = "Successful" ] && echo "lambda updated" && break sleep 1 done
-rw-r--r-- 1 root root 817 Apr 28 13:53 handler.zip InProgress lambda updated Shell cwd was reset to /app [stdout] -rw-r--r-- 1 root root 817 Apr 28 13:53 handler.zip InProgress lambda updated [stderr] Shell cwd was reset to /app
Create ESM with ReportBatchItemFailures
aws lambda create-event-source-mapping \ --function-name orders-consumer \ --event-source-arn arn:aws:sqs:us-east-1:000000000000:orders.fifo \ --batch-size 10 \ --function-response-types ReportBatchItemFailures \ --query '[UUID,State]' --output text
f6db714a-d8f3-4ab3-99e1-33247eea4b03 Creating [stdout] f6db714a-d8f3-4ab3-99e1-33247eea4b03 Creating
Wait ESM enabled
for _ in $(seq 1 20); do S=$(aws lambda list-event-source-mappings --function-name orders-consumer --query 'EventSourceMappings[0].State' --output text) echo "ESM state: $S" [ "$S" = "Enabled" ] && break sleep 1 done
ESM state: Enabled [stdout] ESM state: Enabled
Create apigw-to-sqs role and policy
cat > /tmp/build/apigw-trust.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Principal": {"Service": "apigateway.amazonaws.com"}, "Action": "sts:AssumeRole"}
]
}
EOF
aws iam create-role \
--role-name apigw-to-sqs-role \
--assume-role-policy-document file:///tmp/build/apigw-trust.json \
--query 'Role.Arn' --output text
cat > /tmp/build/apigw-policy.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["sqs:SendMessage", "sqs:GetQueueUrl", "sqs:GetQueueAttributes"],
"Resource": "arn:aws:sqs:us-east-1:000000000000:orders.fifo"
},
{
"Effect": "Allow",
"Action": ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],
"Resource": "*"
}
]
}
EOF
aws iam put-role-policy \
--role-name apigw-to-sqs-role \
--policy-name apigw-sqs-inline \
--policy-document file:///tmp/build/apigw-policy.json
echo "apigw role done"
aws iam get-role --role-name apigw-to-sqs-role --query 'Role.Arn' --output textarn:aws:iam::000000000000:role/apigw-to-sqs-role apigw role done arn:aws:iam::000000000000:role/apigw-to-sqs-role [stdout] arn:aws:iam::000000000000:role/apigw-to-sqs-role apigw role done arn:aws:iam::000000000000:role/apigw-to-sqs-role
Create REST API + /orders + POST method
API_ID=$(aws apigateway create-rest-api --name orders-api --query id --output text) echo "API_ID=$API_ID" echo "$API_ID" > /tmp/build/api_id ROOT_ID=$(aws apigateway get-resources --rest-api-id "$API_ID" --query 'items[?path==`/`].id' --output text) echo "ROOT_ID=$ROOT_ID" RES_ID=$(aws apigateway create-resource --rest-api-id "$API_ID" --parent-id "$ROOT_ID" --path-part orders --query id --output text) echo "RES_ID=$RES_ID" echo "$RES_ID" > /tmp/build/res_id aws apigateway put-method \ --rest-api-id "$API_ID" \ --resource-id "$RES_ID" \ --http-method POST \ --authorization-type NONE \ --query 'httpMethod' --output text
API_ID=ydphp7gmv3 ROOT_ID=yt0wxzdsj6 RES_ID=etqtgsvaxh POST [stdout] API_ID=ydphp7gmv3 ROOT_ID=yt0wxzdsj6 RES_ID=etqtgsvaxh POST
Set up AWS-service integration to SQS
API_ID=$(cat /tmp/build/api_id)
RES_ID=$(cat /tmp/build/res_id)
# AWS service integration to SQS
# URI form: arn:aws:apigateway:{region}:sqs:path/{accountId}/{queueName}
INTEGRATION_URI="arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo"
ROLE_ARN="arn:aws:iam::000000000000:role/apigw-to-sqs-role"
# Request mapping template: convert JSON body -> URL-encoded SendMessage call
# FIFO requires MessageGroupId; content-based dedup is off so we also send MessageDeduplicationId.
read -r -d '' TEMPLATE <<'TMPL'
Action=SendMessage&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))
TMPL
# write request templates JSON
python3 - <<PY > /tmp/build/req-templates.json
import json
tpl = "Action=SendMessage&MessageBody=\$util.urlEncode(\$input.body)&MessageGroupId=\$util.urlEncode(\$input.path('\$.merchant_id'))&MessageDeduplicationId=\$util.urlEncode(\$input.path('\$.order_id'))"
print(json.dumps({"application/json": tpl}))
PY
cat /tmp/build/req-templates.json
aws apigateway put-integration \
--rest-api-id "$API_ID" \
--resource-id "$RES_ID" \
--http-method POST \
--type AWS \
--integration-http-method POST \
--uri "$INTEGRATION_URI" \
--credentials "$ROLE_ARN" \
--request-parameters 'integration.request.header.Content-Type='"'"'application/x-www-form-urlencoded'"'" \
--request-templates file:///tmp/build/req-templates.json \
--passthrough-behavior NEVER \
--query 'type' --output text{"application/json": "Action=SendMessage&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))"}
AWS
[stdout]
{"application/json": "Action=SendMessage&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))"}
AWSSet up method/integration responses
API_ID=$(cat /tmp/build/api_id)
RES_ID=$(cat /tmp/build/res_id)
# Method response: 200 with JSON
aws apigateway put-method-response \
--rest-api-id "$API_ID" \
--resource-id "$RES_ID" \
--http-method POST \
--status-code 200 \
--response-models '{"application/json":"Empty"}' \
--query 'statusCode' --output text
# Integration response: 200 with mapping template that returns simple JSON
cat > /tmp/build/int-resp-templates.json <<'EOF'
{"application/json": "{\"status\":\"queued\"}"}
EOF
aws apigateway put-integration-response \
--rest-api-id "$API_ID" \
--resource-id "$RES_ID" \
--http-method POST \
--status-code 200 \
--selection-pattern "" \
--response-templates file:///tmp/build/int-resp-templates.json \
--query 'statusCode' --output text200 200 [stdout] 200 200
Create dev stage deployment
API_ID=$(cat /tmp/build/api_id) aws apigateway create-deployment \ --rest-api-id "$API_ID" \ --stage-name dev \ --query '[id,createdDate]' --output text
kzabmkf8u4 2026-04-28T13:54:44+00:00 [stdout] kzabmkf8u4 2026-04-28T13:54:44+00:00
POST a first order
API_ID=$(cat /tmp/build/api_id)
URL="http://localstack:4566/restapis/${API_ID}/dev/_user_request_/orders"
echo "URL=$URL"
# First POST
echo "--- POST 1 ---"
curl -s -o /tmp/build/resp1.json -w "HTTP %{http_code}\n" \
-X POST "$URL" \
-H 'Content-Type: application/json' \
-d '{"order_id":"ord-1","merchant_id":"m-1","amount":100}'
cat /tmp/build/resp1.json; echoURL=http://localstack:4566/restapis/ydphp7gmv3/dev/_user_request_/orders
--- POST 1 ---
HTTP 200
{"status":"queued"}
[stdout]
URL=http://localstack:4566/restapis/ydphp7gmv3/dev/_user_request_/orders
--- POST 1 ---
HTTP 200
{"status":"queued"}Verify message processed, no DLQ
sleep 5 echo "--- DDB scan ---" aws dynamodb scan --table-name orders --output json | jq '.Items' echo "--- main queue depth ---" aws sqs get-queue-attributes --queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo --attribute-names ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible --query Attributes echo "--- dlq depth ---" aws sqs get-queue-attributes --queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders-dlq.fifo --attribute-names ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible --query Attributes
--- DDB scan ---
[]
--- main queue depth ---
{
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
--- dlq depth ---
{
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
[stdout]
--- DDB scan ---
[]
--- main queue depth ---
{
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
--- dlq depth ---
{
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}Check lambda logs
echo "--- log groups ---" aws logs describe-log-groups --query 'logGroups[*].logGroupName' --output text echo "--- lambda log streams ---" aws logs describe-log-streams --log-group-name '/aws/lambda/orders-consumer' --order-by LastEventTime --descending --max-items 3 --query 'logStreams[*].logStreamName' --output text 2>&1 | head -20
--- log groups --- --- lambda log streams --- aws: [ERROR]: An error occurred (ResourceNotFoundException) when calling the DescribeLogStreams operation: The specified log group does not exist. [stdout] --- log groups --- --- lambda log streams --- aws: [ERROR]: An error occurred (ResourceNotFoundException) when calling the DescribeLogStreams operation: The specified log group does not exist.
Direct lambda invocation test
# Check whether the queue actually received the first message; check ApproximateNumberOfMessages behavior
# Maybe the message went straight through; check via direct invoke with synthetic SQS event
aws lambda invoke --function-name orders-consumer \
--payload '{"Records":[{"messageId":"m1","body":"{\"order_id\":\"ord-direct\",\"merchant_id\":\"m-x\",\"amount\":7}"}]}' \
--cli-binary-format raw-in-base64-out /tmp/build/inv.json
cat /tmp/build/inv.json; echo
sleep 1
aws dynamodb scan --table-name orders --output json | jq '.Items'{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
{"batchItemFailures": []}
[
{
"created_at": {
"N": "1777384522325"
},
"amount": {
"N": "7"
},
"merchant_id": {
"S": "m-x"
},
"order_id": {
"S": "ord-direct"
}
}
]
[stdout]
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
{"batchItemFailures": []}
[
{
"created_at": {
"N": "1777384522325"
},
"amount": {
"N": "7"
},
"merchant_id": {
"S": "m-x"
},
"order_id": {
"S": "ord-direct"
}
}
]POST verbose to API
# Clean test data and re-test path through API
aws dynamodb delete-item --table-name orders --key '{"order_id":{"S":"ord-direct"}}'
API_ID=$(cat /tmp/build/api_id)
URL="http://localstack:4566/restapis/${API_ID}/dev/_user_request_/orders"
echo "--- POST again with verbose ---"
curl -sv -X POST "$URL" \
-H 'Content-Type: application/json' \
-d '{"order_id":"ord-2","merchant_id":"m-1","amount":42}' 2>&1 | tail -30--- POST again with verbose ---
* Host localstack:4566 was resolved.
* IPv6: (none)
* IPv4: 172.29.0.2
* Trying 172.29.0.2:4566...
* Connected to localstack (172.29.0.2) port 4566
> POST /restapis/ydphp7gmv3/dev/_user_request_/orders HTTP/1.1
> Host: localstack:4566
> User-Agent: curl/8.5.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 52
>
} [52 bytes data]
< HTTP/1.1 200 OK
< Server: TwistedWeb/24.3.0
< Date: Tue, 28 Apr 2026 13:55:32 GMT
< Content-Type: application/json
< Connection: keep-alive
< Content-Length: 19
< x-amzn-RequestId: d1f5ea69-aaa7-4607-aaa3-054d52bcc133
< x-amz-apigw-id: abbd5253=
< X-Amzn-Trace-Id: Root=1-69f0bc54-36acc9be90fcd8d45860d802;Parent=c11d909146cd71b6;Sampled=0
< x-localstack: true
<
{ [19 bytes data]
* Connection #0 to host localstack left intact
{"status":"queued"}
[stdout]
--- POST again with verbose ---
* Host localstack:4566 was resolved.
* IPv6: (none)
* IPv4: 172.29.0.2
* Trying 172.29.0.2:4566...
* Connected to localstack (172.29.0.2) port 4566
> POST /restapis/ydphp7gmv3/dev/_user_request_/orders HTTP/1.1
> Host: localstack:4566
> User-Agent: curl/8.5.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 52
>
} [52 bytes data]
< HTTP/1.1 200 OK
< Server: TwistedWeb/24.3.0
< Date: Tue, 28 Apr 2026 13:55:32 GMT
< Content-Type: application/json
< Connection: keep-alive
< Content-Length: 19
< x-amzn-RequestId: d1f5ea69-aaa7-4607-aaa3-054d52bcc133
< x-amz-apigw-id: abbd5253=
< X-Amzn-Trace-Id: Root=1-69f0bc54-36acc9be90fcd8d45860d802;Parent=c11d909146cd71b6;Sampled=0
< x-localstack: true
<
{ [19 bytes data]
* Connection #0 to host localstack left intact
{"status":"queued"}Poll queue + check ddb/logs
# immediately probe queue for i in 1 2 3 4 5; do D=$(aws sqs get-queue-attributes --queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo --attribute-names ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible --query 'Attributes' --output json) echo "[$i] $D" sleep 1 done echo "--- ddb ---" aws dynamodb scan --table-name orders --output json | jq '.Items' echo "--- log groups ---" aws logs describe-log-groups --query 'logGroups[*].logGroupName' --output text
[1] {
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
[2] {
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
[3] {
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
[4] {
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
[5] {
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
--- ddb ---
[]
--- log groups ---
/aws/lambda/orders-consumer
[stdout]
[1] {
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
[2] {
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
[3] {
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
[4] {
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
[5] {
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
--- ddb ---
[]
--- log groups ---
/aws/lambda/orders-consumerList lambda log streams
aws logs describe-log-streams --log-group-name '/aws/lambda/orders-consumer' --order-by LastEventTime --descending --max-items 3 --query 'logStreams[*].logStreamName' --output text
2026/04/28/[$LATEST]989625e0a7ca26d1235625d57645571a [stdout] 2026/04/28/[$LATEST]989625e0a7ca26d1235625d57645571a
Read lambda logs
aws logs get-log-events --log-group-name '/aws/lambda/orders-consumer' --log-stream-name '2026/04/28/[$LATEST]989625e0a7ca26d1235625d57645571a' --query 'events[*].message' --output text | head -30
START RequestId: 00322c9b-7ba7-407e-9975-50bcff191290 Version: $LATEST END RequestId: 00322c9b-7ba7-407e-9975-50bcff191290 REPORT RequestId: 00322c9b-7ba7-407e-9975-50bcff191290 Duration: 129.60 ms Billed Duration: 130 ms Memory Size: 512 MB Max Memory Used: 512 MB [stdout] START RequestId: 00322c9b-7ba7-407e-9975-50bcff191290 Version: $LATEST END RequestId: 00322c9b-7ba7-407e-9975-50bcff191290 REPORT RequestId: 00322c9b-7ba7-407e-9975-50bcff191290 Duration: 129.60 ms Billed Duration: 130 ms Memory Size: 512 MB Max Memory Used: 512 MB
Test direct queue send
echo "--- direct send to test ESM ---"
aws sqs send-message \
--queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo \
--message-body '{"order_id":"ord-direct-q","merchant_id":"m-9","amount":99}' \
--message-group-id m-9 \
--message-deduplication-id ord-direct-q --query 'MessageId' --output text
sleep 5
echo "--- ddb scan ---"
aws dynamodb scan --table-name orders --output json | jq '.Items'--- direct send to test ESM --- 029ddb42-59fe-451b-b193-3014bf9a2ce3 --- ddb scan --- [] [stdout] --- direct send to test ESM --- 029ddb42-59fe-451b-b193-3014bf9a2ce3 --- ddb scan --- []
Check ESM is firing, queue depth, latest logs
sleep 5 echo "--- queue depth ---" aws sqs get-queue-attributes --queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo --attribute-names ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible --query Attributes echo "--- ddb ---" aws dynamodb scan --table-name orders --output json | jq '.Items' echo "--- lambda log streams ---" aws logs describe-log-streams --log-group-name '/aws/lambda/orders-consumer' --order-by LastEventTime --descending --max-items 3 --query 'logStreams[*].logStreamName' --output text echo "--- ESM details ---" aws lambda list-event-source-mappings --function-name orders-consumer --output json
--- queue depth ---
{
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
--- ddb ---
[
{
"created_at": {
"N": "1777384567516"
},
"amount": {
"N": "99"
},
"merchant_id": {
"S": "m-9"
},
"order_id": {
"S": "ord-direct-q"
}
}
]
--- lambda log streams ---
2026/04/28/[$LATEST]ba44a001d38dfa305766359ff6780351 2026/04/28/[$LATEST]989625e0a7ca26d1235625d57645571a
--- ESM details ---
{
"EventSourceMappings": [
{
"UUID": "f6db714a-d8f3-4ab3-99e1-33247eea4b03",
"BatchSize": 10,
"MaximumBatchingWindowInSeconds": 0,
"EventSourceArn": "arn:aws:sqs:us-east-1:000000000000:orders.fifo",
"FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:orders-consumer",
"LastModified": "2026-04-28T13:53:42.841935+00:00",
"State": "Enabled",
"StateTransitionReason": "USER_INITIATED",
"FunctionResponseTypes": [
"ReportBatchItemFailures"
],
"EventSourceMappingArn": "arn:aws:lambda:us-east-1:000000000000:event-source-mapping:f6db714a-d8f3-4ab3-99e1-33247eea4b03"
}
]
}
[stdout]
--- queue depth ---
{
"ApproximateNumberOfMessages": "0",
"ApproximateNumberOfMessagesNotVisible": "0"
}
--- ddb ---
[
{
"created_at": {
"N": "1777384567516"
},
"amount": {
"N": "99"
},
"merchant_id": {
"S": "m-9"
},
"order_id": {
"S": "ord-direct-q"
}
}
]
--- lambda log streams ---
2026/04/28/[$LATEST]ba44a001d38dfa305766359ff6780351 2026/04/28/[$LATEST]989625e0a7ca26d1235625d57645571a
--- ESM details ---
{
"EventSourceMappings": [
{
"UUID": "f6db714a-d8f3-4ab3-99e1-33247eea4b03",
"BatchSize": 10,
"MaximumBatchingWindowInSeconds": 0,
"EventSourceArn": "arn:aws:sqs:us-east-1:000000000000:orders.fifo",
"FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:orders-consumer",
"LastModified": "2026-04-28T13:53:42.841935+00:00",
"State": "Enabled",
"StateTransitionReason": "USER_INITIATED",
"FunctionResponseTypes": [
"ReportBatchItemFailures"
],
"EventSourceMappingArn": "arn:aws:lambda:us-east-1:000000000000:event-source-mapping:f6db714a-d8f3-4ab3-99e1-33247eea4b03"
}
]
}Show integration config
aws dynamodb delete-item --table-name orders --key '{"order_id":{"S":"ord-direct-q"}}'
API_ID=$(cat /tmp/build/api_id)
RES_ID=$(cat /tmp/build/res_id)
echo "--- current integration ---"
aws apigateway get-integration --rest-api-id "$API_ID" --resource-id "$RES_ID" --http-method POST--- current integration ---
{
"type": "AWS",
"httpMethod": "POST",
"uri": "arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo",
"credentials": "arn:aws:iam::000000000000:role/apigw-to-sqs-role",
"requestParameters": {
"integration.request.header.Content-Type": "application/x-www-form-urlencoded"
},
"requestTemplates": {
"application/json": "Action=SendMessage&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))"
},
"passthroughBehavior": "NEVER",
"timeoutInMillis": 29000,
"cacheNamespace": "etqtgsvaxh",
"cacheKeyParameters": [],
"integrationResponses": {
"200": {
"statusCode": "200",
"responseTemplates": {
"application/json": "{\"status\":\"queued\"}"
}
}
}
}
[stdout]
--- current integration ---
{
"type": "AWS",
"httpMethod": "POST",
"uri": "arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo",
"credentials": "arn:aws:iam::000000000000:role/apigw-to-sqs-role",
"requestParameters": {
"integration.request.header.Content-Type": "application/x-www-form-urlencoded"
},
"requestTemplates": {
"application/json": "Action=SendMessage&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))"
},
"passthroughBehavior": "NEVER",
"timeoutInMillis": 29000,
"cacheNamespace": "etqtgsvaxh",
"cacheKeyParameters": [],
"integrationResponses": {
"200": {
"statusCode": "200",
"responseTemplates": {
"application/json": "{\"status\":\"queued\"}"
}
}
}
}Test invoke method for diagnostics
API_ID=$(cat /tmp/build/api_id)
RES_ID=$(cat /tmp/build/res_id)
# test-invoke-method to see what happens
aws apigateway test-invoke-method \
--rest-api-id "$API_ID" \
--resource-id "$RES_ID" \
--http-method POST \
--headers Content-Type=application/json \
--body '{"order_id":"ord-test","merchant_id":"m-1","amount":11}' 2>&1 | head -60{
"status": 200,
"body": "{\"status\":\"queued\"}",
"headers": {
"X-Amzn-Trace-Id": "Root=1-69f0bca8-3f1c3a48b92d678831ac3889;Parent=10ab31ab9dd20ecb;Sampled=0",
"Content-Type": "application/json"
},
"multiValueHeaders": {
"X-Amzn-Trace-Id": [
"Root=1-69f0bca8-3f1c3a48b92d678831ac3889;Parent=10ab31ab9dd20ecb;Sampled=0"
],
"Content-Type": [
"application/json"
]
},
"log": "Execution log for request 172a98fc-5a03-4b45-979f-4691541c05ed\nTue Apr 28 13:56:56 UTC 2026 : Starting execution for request: 172a98fc-5a03-4b45-979f-4691541c05ed\nTue Apr 28 13:56:56 UTC 2026 : HTTP Method: POST, Resource Path: /orders\nTue Apr 28 13:56:56 UTC 2026 : Method request path: {}\nTue Apr 28 13:56:56 UTC 2026 : Method request query string: {}\nTue Apr 28 13:56:56 UTC 2026 : Method request headers: {Content-Type=application/json}\nTue Apr 28 13:56:56 UTC 2026 : Method request body before transformations: {\"order_id\":\"ord-test\",\"merchant_id\":\"m-1\",\"amount\":11}\nTue Apr 28 13:56:56 UTC 2026 : Endpoint request URI: arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo\nTue Apr 28 13:56:56 UTC 2026 : Endpoint request headers: {Accept=application/json, Connection=keep-alive, User-Agent=AmazonAPIGateway_ydphp7gmv3, X-Amzn-Trace-Id=Root=1-69f0bca8-3f1c3a48b92d678831ac3889;Parent=10ab31ab9dd20ecb;Sampled=0, Authorization=AWS4-HMAC-SHA256 Credential=LSIAQAAAAAAAFAQJGMHH/20160623/us-east-1/sqs/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=1234, x-localstack-data={\"service_principal\":\"apigateway\",\"source_arn\":\"arn:aws:execute-api:us-east-1:000000000000:ydphp7gmv3/None/POST/orders\"}, Host=sqs.us-east-1.localhost.localstack.cloud:4566}\nTue Apr 28 13:56:56 UTC 2026 : Endpoint request body after transformations: Action=SendMessage&MessageBody=%7B%22order_id%22%3A%22ord-test%22%2C%22merchant_id%22%3A%22m-1%22%2C%22amount%22%3A11%7D&MessageGroupId=m-1&MessageDeduplicationId=ord-test\nTue Apr 28 13:56:56 UTC 2026 : Sending request to arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo\nTue Apr 28 13:56:56 UTC 2026 : Received response. Status: 404, Integration latency: 150 ms\nTue Apr 28 13:56:56 UTC 2026 : Endpoint response headers: {Server=TwistedWeb/24.3.0, Date=Tue, 28 Apr 2026 13:56:56 GMT, Content-Type=text/plain; charset=utf-8, Content-Length=28, x-localstack=true}\nTue Apr 28 13:56:56 UTC 2026 : Endpoint response body before transformations: <UnknownOperationException/>\nTue Apr 28 13:56:56 UTC 2026 : Method response body after transformations: {\"status\":\"queued\"}\nTue Apr 28 13:56:56 UTC 2026 : Method response headers: {X-Amzn-Trace-Id=Root=1-69f0bca8-3f1c3a48b92d678831ac3889;Parent=10ab31ab9dd20ecb;Sampled=0, Content-Type=application/json}\nTue Apr 28 13:56:56 UTC 2026 : Successfully completed execution\nTue Apr 28 13:56:56 UTC 2026 : Method completed with status: 200\n",
"latency": 0
}
[stdout]
{
"status": 200,
"body": "{\"status\":\"queued\"}",
"headers": {
"X-Amzn-Trace-Id": "Root=1-69f0bca8-3f1c3a48b92d678831ac3889;Parent=10ab31ab9dd20ecb;Sampled=0",
"Content-Type": "application/json"
},
"multiValueHeaders": {
"X-Amzn-Trace-Id": [
"Root=1-69f0bca8-3f1c3a48b92d678831ac3889;Parent=10ab31ab9dd20ecb;Sampled=0"
],
"Content-Type": [
"application/json"
]
},
"log": "Execution log for request 172a98fc-5a03-4b45-979f-4691541c05ed\nTue Apr 28 13:56:56 UTC 2026 : Starting execution for request: 172a98fc-5a03-4b45-979f-4691541c05ed\nTue Apr 28 13:56:56 UTC 2026 : HTTP Method: POST, Resource Path: /orders\nTue Apr 28 13:56:56 UTC 2026 : Method request path: {}\nTue Apr 28 13:56:56 UTC 2026 : Method request query string: {}\nTue Apr 28 13:56:56 UTC 2026 : Method request headers: {Content-Type=application/json}\nTue Apr 28 13:56:56 UTC 2026 : Method request body before transformations: {\"order_id\":\"ord-test\",\"merchant_id\":\"m-1\",\"amount\":11}\nTue Apr 28 13:56:56 UTC 2026 : Endpoint request URI: arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo\nTue Apr 28 13:56:56 UTC 2026 : Endpoint request headers: {Accept=application/json, Connection=keep-alive, User-Agent=AmazonAPIGateway_ydphp7gmv3, X-Amzn-Trace-Id=Root=1-69f0bca8-3f1c3a48b92d678831ac3889;Parent=10ab31ab9dd20ecb;Sampled=0, Authorization=AWS4-HMAC-SHA256 Credential=LSIAQAAAAAAAFAQJGMHH/20160623/us-east-1/sqs/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=1234, x-localstack-data={\"service_principal\":\"apigateway\",\"source_arn\":\"arn:aws:execute-api:us-east-1:000000000000:ydphp7gmv3/None/POST/orders\"}, Host=sqs.us-east-1.localhost.localstack.cloud:4566}\nTue Apr 28 13:56:56 UTC 2026 : Endpoint request body after transformations: Action=SendMessage&MessageBody=%7B%22order_id%22%3A%22ord-test%22%2C%22merchant_id%22%3A%22m-1%22%2C%22amount%22%3A11%7D&MessageGroupId=m-1&MessageDeduplicationId=ord-test\nTue Apr 28 13:56:56 UTC 2026 : Sending request to arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo\nTue Apr 28 13:56:56 UTC 2026 : Received response. Status: 404, Integration latency: 150 ms\nTue Apr 28 13:56:56 UTC 2026 : Endpoint response headers: {Server=TwistedWeb/24.3.0, Date=Tue, 28 Apr 2026 13:56:56 GMT, Content-Type=text/plain; charset=utf-8, Content-Length=28, x-localstack=true}\nTue Apr 28 13:56:56 UTC 2026 : Endpoint response body before transformations: <UnknownOperationException/>\nTue Apr 28 13:56:56 UTC 2026 : Method response body after transformations: {\"status\":\"queued\"}\nTue Apr 28 13:56:56 UTC 2026 : Method response headers: {X-Amzn-Trace-Id=Root=1-69f0bca8-3f1c3a48b92d678831ac3889;Parent=10ab31ab9dd20ecb;Sampled=0, Content-Type=application/json}\nTue Apr 28 13:56:56 UTC 2026 : Successfully completed execution\nTue Apr 28 13:56:56 UTC 2026 : Method completed with status: 200\n",
"latency": 0
}Switch integration to action-style URI
API_ID=$(cat /tmp/build/api_id)
RES_ID=$(cat /tmp/build/res_id)
# Try action-style URI with QueueUrl in the body
INTEGRATION_URI="arn:aws:apigateway:us-east-1:sqs:action/SendMessage"
python3 - <<'PY' > /tmp/build/req-templates.json
import json
qurl = "http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo"
tpl = (
"Action=SendMessage"
"&QueueUrl=" + ''.join(f"%{ord(c):02X}" if not c.isalnum() and c not in '-_.~' else c for c in qurl) +
"&MessageBody=$util.urlEncode($input.body)"
"&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))"
"&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))"
)
print(json.dumps({"application/json": tpl}))
PY
cat /tmp/build/req-templates.json
echo
aws apigateway update-integration \
--rest-api-id "$API_ID" \
--resource-id "$RES_ID" \
--http-method POST \
--patch-operations \
op=replace,path=/uri,value="$INTEGRATION_URI" \
--query 'uri' --output text
aws apigateway update-integration \
--rest-api-id "$API_ID" \
--resource-id "$RES_ID" \
--http-method POST \
--patch-operations \
op=replace,path=/requestTemplates/application~1json,value="$(cat /tmp/build/req-templates.json | python3 -c 'import json,sys; print(json.load(sys.stdin)["application/json"])')" \
--query 'requestTemplates' --output jsonExit code 252
{"application/json": "Action=SendMessage&QueueUrl=http%3A%2F%2Fsqs.us-east-1.localhost.localstack.cloud%3A4566%2F000000000000%2Forders.fifo&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))"}
arn:aws:apigateway:us-east-1:sqs:action/SendMessage
aws: [ERROR]: An error occurred (ParamValidation): Error parsing parameter '--patch-operations': Expected: ',', received: ''' for input:
op=replace,path=/requestTemplates/application~1json,value=Action=SendMessage&QueueUrl=http%3A%2F%2Fsqs.us-east-1.localhost.localstack.cloud%3A4566%2F000000000000%2Forders.fifo&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))
^
[error] tool reported failureUpdate integration request template via cli-input-json
API_ID=$(cat /tmp/build/api_id)
RES_ID=$(cat /tmp/build/res_id)
# Use a JSON-valued patch via cli-input-json
TPL=$(python3 -c '
qurl = "http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo"
enc = "".join(f"%{ord(c):02X}" if not c.isalnum() and c not in "-_.~" else c for c in qurl)
print("Action=SendMessage&QueueUrl=" + enc + "&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path(\047$.merchant_id\047))&MessageDeduplicationId=$util.urlEncode($input.path(\047$.order_id\047))")
')
echo "TPL=$TPL"
python3 - "$TPL" <<'PY' > /tmp/build/patch.json
import json,sys
tpl = sys.argv[1]
print(json.dumps({
"restApiId": "PLACEHOLDER",
"resourceId": "PLACEHOLDER",
"httpMethod": "POST",
"patchOperations": [
{"op":"replace","path":"/requestTemplates/application~1json","value": tpl}
]
}))
PY
# Substitute IDs
python3 - <<PY
import json
with open('/tmp/build/patch.json') as f: d=json.load(f)
d["restApiId"]="$API_ID"
d["resourceId"]="$RES_ID"
with open('/tmp/build/patch.json','w') as f: json.dump(d,f)
PY
cat /tmp/build/patch.json | head -c 400; echo
aws apigateway update-integration --cli-input-json file:///tmp/build/patch.json --query 'requestTemplates' --output jsonTPL=Action=SendMessage&QueueUrl=http%3A%2F%2Fsqs.us-east-1.localhost.localstack.cloud%3A4566%2F000000000000%2Forders.fifo&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))
{"restApiId": "ydphp7gmv3", "resourceId": "etqtgsvaxh", "httpMethod": "POST", "patchOperations": [{"op": "replace", "path": "/requestTemplates/application~1json", "value": "Action=SendMessage&QueueUrl=http%3A%2F%2Fsqs.us-east-1.localhost.localstack.cloud%3A4566%2F000000000000%2Forders.fifo&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&Message
{
"application/json": "Action=SendMessage&QueueUrl=http%3A%2F%2Fsqs.us-east-1.localhost.localstack.cloud%3A4566%2F000000000000%2Forders.fifo&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))"
}
[stdout]
TPL=Action=SendMessage&QueueUrl=http%3A%2F%2Fsqs.us-east-1.localhost.localstack.cloud%3A4566%2F000000000000%2Forders.fifo&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))
{"restApiId": "ydphp7gmv3", "resourceId": "etqtgsvaxh", "httpMethod": "POST", "patchOperations": [{"op": "replace", "path": "/requestTemplates/application~1json", "value": "Action=SendMessage&QueueUrl=http%3A%2F%2Fsqs.us-east-1.localhost.localstack.cloud%3A4566%2F000000000000%2Forders.fifo&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&Message
{
"application/json": "Action=SendMessage&QueueUrl=http%3A%2F%2Fsqs.us-east-1.localhost.localstack.cloud%3A4566%2F000000000000%2Forders.fifo&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))"
}Redeploy and test action-style integration
API_ID=$(cat /tmp/build/api_id)
aws apigateway create-deployment --rest-api-id "$API_ID" --stage-name dev --query id --output text
# Now test
RES_ID=$(cat /tmp/build/res_id)
aws apigateway test-invoke-method \
--rest-api-id "$API_ID" \
--resource-id "$RES_ID" \
--http-method POST \
--headers Content-Type=application/json \
--body '{"order_id":"ord-test","merchant_id":"m-1","amount":11}' --query 'log' --output text 2>&1 | head -30d6wpnb9gbu
Execution log for request 94e190d2-8afe-4c2d-a4f5-015607d9153b
Tue Apr 28 13:57:38 UTC 2026 : Starting execution for request: 94e190d2-8afe-4c2d-a4f5-015607d9153b
Tue Apr 28 13:57:38 UTC 2026 : HTTP Method: POST, Resource Path: /orders
Tue Apr 28 13:57:38 UTC 2026 : Method request path: {}
Tue Apr 28 13:57:38 UTC 2026 : Method request query string: {}
Tue Apr 28 13:57:38 UTC 2026 : Method request headers: {Content-Type=application/json}
Tue Apr 28 13:57:38 UTC 2026 : Method request body before transformations: {"order_id":"ord-test","merchant_id":"m-1","amount":11}
Tue Apr 28 13:57:38 UTC 2026 : Endpoint request URI: arn:aws:apigateway:us-east-1:sqs:action/SendMessage
Tue Apr 28 13:57:38 UTC 2026 : Endpoint request headers: {Accept=application/json, Connection=keep-alive, User-Agent=AmazonAPIGateway_ydphp7gmv3, X-Amzn-Trace-Id=Root=1-69f0bcd2-ff270a5443ad0e6f2896d227;Parent=8f21df991fda6c71;Sampled=0, Authorization=AWS4-HMAC-SHA256 Credential=LSIAQAAAAAAAFAQJGMHH/20160623/us-east-1/sqs/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=1234, x-localstack-data={"service_principal":"apigateway","source_arn":"arn:aws:execute-api:us-east-1:000000000000:ydphp7gmv3/None/POST/orders"}, Host=sqs.us-east-1.localhost.localstack.cloud:4566}
Tue Apr 28 13:57:38 UTC 2026 : Endpoint request body after transformations: Action=SendMessage&QueueUrl=http%3A%2F%2Fsqs.us-east-1.localhost.localstack.cloud%3A4566%2F000000000000%2Forders.fifo&MessageBody=%7B%22order_id%22%3A%22ord-test%22%2C%22merchant_id%22%3A%22m-1%22%2C%22amount%22%3A11%7D&MessageGroupId=m-1&MessageDeduplicationId=ord-test
Tue Apr 28 13:57:38 UTC 2026 : Sending request to arn:aws:apigateway:us-east-1:sqs:action/SendMessage
Tue Apr 28 13:57:38 UTC 2026 : Received response. Status: 400, Integration latency: 150 ms
Tue Apr 28 13:57:38 UTC 2026 : Endpoint response headers: {Server=TwistedWeb/24.3.0, Date=Tue, 28 Apr 2026 13:57:38 GMT, Content-Type=application/json, Content-Length=224, x-amzn-RequestId=57b80bab-5e02-4879-8e0d-c26f2da074a8, x-localstack=true}
Tue Apr 28 13:57:38 UTC 2026 : Endpoint response body before transformations: {"ErrorResponse": {"Error": {"Code": "AWS.SimpleQueueService.NonExistentQueue", "Message": "The specified queue does not exist for this wsdl version.", "Type": "Sender"}, "RequestId": "57b80bab-5e02-4879-8e0d-c26f2da074a8"}}
Tue Apr 28 13:57:38 UTC 2026 : Method response body after transformations: {"status":"queued"}
Tue Apr 28 13:57:38 UTC 2026 : Method response headers: {X-Amzn-Trace-Id=Root=1-69f0bcd2-ff270a5443ad0e6f2896d227;Parent=8f21df991fda6c71;Sampled=0, Content-Type=application/json}
Tue Apr 28 13:57:38 UTC 2026 : Successfully completed execution
Tue Apr 28 13:57:38 UTC 2026 : Method completed with status: 200
[stdout]
d6wpnb9gbu
Execution log for request 94e190d2-8afe-4c2d-a4f5-015607d9153b
Tue Apr 28 13:57:38 UTC 2026 : Starting execution for request: 94e190d2-8afe-4c2d-a4f5-015607d9153b
Tue Apr 28 13:57:38 UTC 2026 : HTTP Method: POST, Resource Path: /orders
Tue Apr 28 13:57:38 UTC 2026 : Method request path: {}
Tue Apr 28 13:57:38 UTC 2026 : Method request query string: {}
Tue Apr 28 13:57:38 UTC 2026 : Method request headers: {Content-Type=application/json}
Tue Apr 28 13:57:38 UTC 2026 : Method request body before transformations: {"order_id":"ord-test","merchant_id":"m-1","amount":11}
Tue Apr 28 13:57:38 UTC 2026 : Endpoint request URI: arn:aws:apigateway:us-east-1:sqs:action/SendMessage
Tue Apr 28 13:57:38 UTC 2026 : Endpoint request headers: {Accept=application/json, Connection=keep-alive, User-Agent=AmazonAPIGateway_ydphp7gmv3, X-Amzn-Trace-Id=Root=1-69f0bcd2-ff270a5443ad0e6f2896d227;Parent=8f21df991fda6c71;Sampled=0, Authorization=AWS4-HMAC-SHA256 Credential=LSIAQAAAAAAAFAQJGMHH/20160623/us-east-1/sqs/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=1234, x-localstack-data={"service_principal":"apigateway","source_arn":"arn:aws:execute-api:us-east-1:000000000000:ydphp7gmv3/None/POST/orders"}, Host=sqs.us-east-1.localhost.localstack.cloud:4566}
Tue Apr 28 13:57:38 UTC 2026 : Endpoint request body after transformations: Action=SendMessage&QueueUrl=http%3A%2F%2Fsqs.us-east-1.localhost.localstack.cloud%3A4566%2F000000000000%2Forders.fifo&MessageBody=%7B%22order_id%22%3A%22ord-test%22%2C%22merchant_id%22%3A%22m-1%22%2C%22amount%22%3A11%7D&MessageGroupId=m-1&MessageDeduplicationId=ord-test
Tue Apr 28 13:57:38 UTC 2026 : Sending request to arn:aws:apigateway:us-east-1:sqs:action/SendMessage
Tue Apr 28 13:57:38 UTC 2026 : Received response. Status: 400, Integration latency: 150 ms
Tue Apr 28 13:57:38 UTC 2026 : Endpoint response headers: {Server=TwistedWeb/24.3.0, Date=Tue, 28 Apr 2026 13:57:38 GMT, Content-Type=application/json, Content-Length=224, x-amzn-RequestId=57b80bab-5e02-4879-8e0d-c26f2da074a8, x-localstack=true}
Tue Apr 28 13:57:38 UTC 2026 : Endpoint response body before transformations: {"ErrorResponse": {"Error": {"Code": "AWS.SimpleQueueService.NonExistentQueue", "Message": "The specified queue does not exist for this wsdl version.", "Type": "Sender"}, "RequestId": "57b80bab-5e02-4879-8e0d-c26f2da074a8"}}
Tue Apr 28 13:57:38 UTC 2026 : Method response body after transformations: {"status":"queued"}
Tue Apr 28 13:57:38 UTC 2026 : Method response headers: {X-Amzn-Trace-Id=Root=1-69f0bcd2-ff270a5443ad0e6f2896d227;Parent=8f21df991fda6c71;Sampled=0, Content-Type=application/json}
Tue Apr 28 13:57:38 UTC 2026 : Successfully completed execution
Tue Apr 28 13:57:38 UTC 2026 : Method completed with status: 200Path-style URI with form body
API_ID=$(cat /tmp/build/api_id)
RES_ID=$(cat /tmp/build/res_id)
# Patch URI back to path style and template back to no QueueUrl
TPL=$(python3 -c "print(\"Action=SendMessage&MessageBody=\$util.urlEncode(\$input.body)&MessageGroupId=\$util.urlEncode(\$input.path('\$.merchant_id'))&MessageDeduplicationId=\$util.urlEncode(\$input.path('\$.order_id'))\")")
echo "$TPL"
python3 - <<PY > /tmp/build/patch.json
import json
print(json.dumps({
"restApiId": "$API_ID",
"resourceId": "$RES_ID",
"httpMethod": "POST",
"patchOperations": [
{"op":"replace","path":"/uri","value":"arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo"},
{"op":"replace","path":"/requestTemplates/application~1json","value": $(python3 -c "import json; print(json.dumps('''$TPL'''))")}
]
}))
PY
cat /tmp/build/patch.json
aws apigateway update-integration --cli-input-json file:///tmp/build/patch.json --query 'uri' --output text
aws apigateway create-deployment --rest-api-id "$API_ID" --stage-name dev --query id --output text
aws apigateway test-invoke-method \
--rest-api-id "$API_ID" \
--resource-id "$RES_ID" \
--http-method POST \
--headers Content-Type=application/json \
--body '{"order_id":"ord-test","merchant_id":"m-1","amount":11}' --query 'log' --output text 2>&1 | head -30Action=SendMessage&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))
{"restApiId": "ydphp7gmv3", "resourceId": "etqtgsvaxh", "httpMethod": "POST", "patchOperations": [{"op": "replace", "path": "/uri", "value": "arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo"}, {"op": "replace", "path": "/requestTemplates/application~1json", "value": "Action=SendMessage&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))"}]}
arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo
9pjrbdvlbz
Execution log for request 38ac17f3-b62a-4187-8392-87d1aa6c1c7f
Tue Apr 28 13:58:06 UTC 2026 : Starting execution for request: 38ac17f3-b62a-4187-8392-87d1aa6c1c7f
Tue Apr 28 13:58:06 UTC 2026 : HTTP Method: POST, Resource Path: /orders
Tue Apr 28 13:58:06 UTC 2026 : Method request path: {}
Tue Apr 28 13:58:06 UTC 2026 : Method request query string: {}
Tue Apr 28 13:58:06 UTC 2026 : Method request headers: {Content-Type=application/json}
Tue Apr 28 13:58:06 UTC 2026 : Method request body before transformations: {"order_id":"ord-test","merchant_id":"m-1","amount":11}
Tue Apr 28 13:58:06 UTC 2026 : Endpoint request URI: arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo
Tue Apr 28 13:58:06 UTC 2026 : Endpoint request headers: {Accept=application/json, Connection=keep-alive, User-Agent=AmazonAPIGateway_ydphp7gmv3, X-Amzn-Trace-Id=Root=1-69f0bcee-bd10a2583bd31febf2014cb3;Parent=e9db56a7185e654b;Sampled=0, Authorization=AWS4-HMAC-SHA256 Credential=LSIAQAAAAAAAFAQJGMHH/20160623/us-east-1/sqs/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=1234, x-localstack-data={"service_principal":"apigateway","source_arn":"arn:aws:execute-api:us-east-1:000000000000:ydphp7gmv3/None/POST/orders"}, Host=sqs.us-east-1.localhost.localstack.cloud:4566}
Tue Apr 28 13:58:06 UTC 2026 : Endpoint request body after transformations: Action=SendMessage&MessageBody=%7B%22order_id%22%3A%22ord-test%22%2C%22merchant_id%22%3A%22m-1%22%2C%22amount%22%3A11%7D&MessageGroupId=m-1&MessageDeduplicationId=ord-test
Tue Apr 28 13:58:06 UTC 2026 : Sending request to arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo
Tue Apr 28 13:58:06 UTC 2026 : Received response. Status: 404, Integration latency: 150 ms
Tue Apr 28 13:58:06 UTC 2026 : Endpoint response headers: {Server=TwistedWeb/24.3.0, Date=Tue, 28 Apr 2026 13:58:06 GMT, Content-Type=text/plain; charset=utf-8, Content-Length=28, x-localstack=true}
Tue Apr 28 13:58:06 UTC 2026 : Endpoint response body before transformations: <UnknownOperationException/>
Tue Apr 28 13:58:06 UTC 2026 : Method response body after transformations: {"status":"queued"}
Tue Apr 28 13:58:06 UTC 2026 : Method response headers: {X-Amzn-Trace-Id=Root=1-69f0bcee-bd10a2583bd31febf2014cb3;Parent=e9db56a7185e654b;Sampled=0, Content-Type=application/json}
Tue Apr 28 13:58:06 UTC 2026 : Successfully completed execution
Tue Apr 28 13:58:06 UTC 2026 : Method completed with status: 200
[stdout]
Action=SendMessage&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))
{"restApiId": "ydphp7gmv3", "resourceId": "etqtgsvaxh", "httpMethod": "POST", "patchOperations": [{"op": "replace", "path": "/uri", "value": "arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo"}, {"op": "replace", "path": "/requestTemplates/application~1json", "value": "Action=SendMessage&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))"}]}
arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo
9pjrbdvlbz
Execution log for request 38ac17f3-b62a-4187-8392-87d1aa6c1c7f
Tue Apr 28 13:58:06 UTC 2026 : Starting execution for request: 38ac17f3-b62a-4187-8392-87d1aa6c1c7f
Tue Apr 28 13:58:06 UTC 2026 : HTTP Method: POST, Resource Path: /orders
Tue Apr 28 13:58:06 UTC 2026 : Method request path: {}
Tue Apr 28 13:58:06 UTC 2026 : Method request query string: {}
Tue Apr 28 13:58:06 UTC 2026 : Method request headers: {Content-Type=application/json}
Tue Apr 28 13:58:06 UTC 2026 : Method request body before transformations: {"order_id":"ord-test","merchant_id":"m-1","amount":11}
Tue Apr 28 13:58:06 UTC 2026 : Endpoint request URI: arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo
Tue Apr 28 13:58:06 UTC 2026 : Endpoint request headers: {Accept=application/json, Connection=keep-alive, User-Agent=AmazonAPIGateway_ydphp7gmv3, X-Amzn-Trace-Id=Root=1-69f0bcee-bd10a2583bd31febf2014cb3;Parent=e9db56a7185e654b;Sampled=0, Authorization=AWS4-HMAC-SHA256 Credential=LSIAQAAAAAAAFAQJGMHH/20160623/us-east-1/sqs/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=1234, x-localstack-data={"service_principal":"apigateway","source_arn":"arn:aws:execute-api:us-east-1:000000000000:ydphp7gmv3/None/POST/orders"}, Host=sqs.us-east-1.localhost.localstack.cloud:4566}
Tue Apr 28 13:58:06 UTC 2026 : Endpoint request body after transformations: Action=SendMessage&MessageBody=%7B%22order_id%22%3A%22ord-test%22%2C%22merchant_id%22%3A%22m-1%22%2C%22amount%22%3A11%7D&MessageGroupId=m-1&MessageDeduplicationId=ord-test
Tue Apr 28 13:58:06 UTC 2026 : Sending request to arn:aws:apigateway:us-east-1:sqs:path/000000000000/orders.fifo
Tue Apr 28 13:58:06 UTC 2026 : Received response. Status: 404, Integration latency: 150 ms
Tue Apr 28 13:58:06 UTC 2026 : Endpoint response headers: {Server=TwistedWeb/24.3.0, Date=Tue, 28 Apr 2026 13:58:06 GMT, Content-Type=text/plain; charset=utf-8, Content-Length=28, x-localstack=true}
Tue Apr 28 13:58:06 UTC 2026 : Endpoint response body before transformations: <UnknownOperationException/>
Tue Apr 28 13:58:06 UTC 2026 : Method response body after transformations: {"status":"queued"}
Tue Apr 28 13:58:06 UTC 2026 : Method response headers: {X-Amzn-Trace-Id=Root=1-69f0bcee-bd10a2583bd31febf2014cb3;Parent=e9db56a7185e654b;Sampled=0, Content-Type=application/json}
Tue Apr 28 13:58:06 UTC 2026 : Successfully completed execution
Tue Apr 28 13:58:06 UTC 2026 : Method completed with status: 200Try action-style with bare queue name
API_ID=$(cat /tmp/build/api_id)
RES_ID=$(cat /tmp/build/res_id)
# Action style with QueueUrl as the queue name only (localstack often accepts plain name or the path part)
TPL=$(python3 -c "
import urllib.parse as u
qurl = u.quote('http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo', safe='')
print(\"Action=SendMessage&QueueUrl=\" + qurl + \"&MessageBody=\$util.urlEncode(\$input.body)&MessageGroupId=\$util.urlEncode(\$input.path('\$.merchant_id'))&MessageDeduplicationId=\$util.urlEncode(\$input.path('\$.order_id'))\")
")
# Try queue name alternative
TPL2=$(python3 -c "
print(\"Action=SendMessage&QueueUrl=orders.fifo&MessageBody=\$util.urlEncode(\$input.body)&MessageGroupId=\$util.urlEncode(\$input.path('\$.merchant_id'))&MessageDeduplicationId=\$util.urlEncode(\$input.path('\$.order_id'))\")
")
echo "TPL2=$TPL2"
python3 - <<PY > /tmp/build/patch.json
import json
print(json.dumps({
"restApiId": "$API_ID",
"resourceId": "$RES_ID",
"httpMethod": "POST",
"patchOperations": [
{"op":"replace","path":"/uri","value":"arn:aws:apigateway:us-east-1:sqs:action/SendMessage"},
{"op":"replace","path":"/requestTemplates/application~1json","value": $(python3 -c "import json; print(json.dumps('''$TPL2'''))")}
]
}))
PY
aws apigateway update-integration --cli-input-json file:///tmp/build/patch.json --query 'requestTemplates' --output json
aws apigateway create-deployment --rest-api-id "$API_ID" --stage-name dev --query id --output text
aws apigateway test-invoke-method \
--rest-api-id "$API_ID" \
--resource-id "$RES_ID" \
--http-method POST \
--headers Content-Type=application/json \
--body '{"order_id":"ord-test","merchant_id":"m-1","amount":11}' --query 'log' --output text 2>&1 | tail -15TPL2=Action=SendMessage&QueueUrl=orders.fifo&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))
{
"application/json": "Action=SendMessage&QueueUrl=orders.fifo&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))"
}
0mbxwmkvva
Tue Apr 28 13:58:27 UTC 2026 : Method request query string: {}
Tue Apr 28 13:58:27 UTC 2026 : Method request headers: {Content-Type=application/json}
Tue Apr 28 13:58:27 UTC 2026 : Method request body before transformations: {"order_id":"ord-test","merchant_id":"m-1","amount":11}
Tue Apr 28 13:58:27 UTC 2026 : Endpoint request URI: arn:aws:apigateway:us-east-1:sqs:action/SendMessage
Tue Apr 28 13:58:27 UTC 2026 : Endpoint request headers: {Accept=application/json, Connection=keep-alive, User-Agent=AmazonAPIGateway_ydphp7gmv3, X-Amzn-Trace-Id=Root=1-69f0bd02-a86ead64f8f6f83077356161;Parent=5190dafa57ddfc66;Sampled=0, Authorization=AWS4-HMAC-SHA256 Credential=LSIAQAAAAAAAFAQJGMHH/20160623/us-east-1/sqs/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=1234, x-localstack-data={"service_principal":"apigateway","source_arn":"arn:aws:execute-api:us-east-1:000000000000:ydphp7gmv3/None/POST/orders"}, Host=sqs.us-east-1.localhost.localstack.cloud:4566}
Tue Apr 28 13:58:27 UTC 2026 : Endpoint request body after transformations: Action=SendMessage&QueueUrl=orders.fifo&MessageBody=%7B%22order_id%22%3A%22ord-test%22%2C%22merchant_id%22%3A%22m-1%22%2C%22amount%22%3A11%7D&MessageGroupId=m-1&MessageDeduplicationId=ord-test
Tue Apr 28 13:58:27 UTC 2026 : Sending request to arn:aws:apigateway:us-east-1:sqs:action/SendMessage
Tue Apr 28 13:58:27 UTC 2026 : Received response. Status: 400, Integration latency: 150 ms
Tue Apr 28 13:58:27 UTC 2026 : Endpoint response headers: {Server=TwistedWeb/24.3.0, Date=Tue, 28 Apr 2026 13:58:27 GMT, Content-Type=application/json, Content-Length=224, x-amzn-RequestId=cb5f0c6a-0822-4262-bf66-4b4ed8c2b934, x-localstack=true}
Tue Apr 28 13:58:27 UTC 2026 : Endpoint response body before transformations: {"ErrorResponse": {"Error": {"Code": "AWS.SimpleQueueService.NonExistentQueue", "Message": "The specified queue does not exist for this wsdl version.", "Type": "Sender"}, "RequestId": "cb5f0c6a-0822-4262-bf66-4b4ed8c2b934"}}
Tue Apr 28 13:58:27 UTC 2026 : Method response body after transformations: {"status":"queued"}
Tue Apr 28 13:58:27 UTC 2026 : Method response headers: {X-Amzn-Trace-Id=Root=1-69f0bd02-a86ead64f8f6f83077356161;Parent=5190dafa57ddfc66;Sampled=0, Content-Type=application/json}
Tue Apr 28 13:58:27 UTC 2026 : Successfully completed execution
Tue Apr 28 13:58:27 UTC 2026 : Method completed with status: 200
[stdout]
TPL2=Action=SendMessage&QueueUrl=orders.fifo&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))
{
"application/json": "Action=SendMessage&QueueUrl=orders.fifo&MessageBody=$util.urlEncode($input.body)&MessageGroupId=$util.urlEncode($input.path('$.merchant_id'))&MessageDeduplicationId=$util.urlEncode($input.path('$.order_id'))"
}
0mbxwmkvva
Tue Apr 28 13:58:27 UTC 2026 : Method request query string: {}
Tue Apr 28 13:58:27 UTC 2026 : Method request headers: {Content-Type=application/json}
Tue Apr 28 13:58:27 UTC 2026 : Method request body before transformations: {"order_id":"ord-test","merchant_id":"m-1","amount":11}
Tue Apr 28 13:58:27 UTC 2026 : Endpoint request URI: arn:aws:apigateway:us-east-1:sqs:action/SendMessage
Tue Apr 28 13:58:27 UTC 2026 : Endpoint request headers: {Accept=application/json, Connection=keep-alive, User-Agent=AmazonAPIGateway_ydphp7gmv3, X-Amzn-Trace-Id=Root=1-69f0bd02-a86ead64f8f6f83077356161;Parent=5190dafa57ddfc66;Sampled=0, Authorization=AWS4-HMAC-SHA256 Credential=LSIAQAAAAAAAFAQJGMHH/20160623/us-east-1/sqs/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=1234, x-localstack-data={"service_principal":"apigateway","source_arn":"arn:aws:execute-api:us-east-1:000000000000:ydphp7gmv3/None/POST/orders"}, Host=sqs.us-east-1.localhost.localstack.cloud:4566}
Tue Apr 28 13:58:27 UTC 2026 : Endpoint request body after transformations: Action=SendMessage&QueueUrl=orders.fifo&MessageBody=%7B%22order_id%22%3A%22ord-test%22%2C%22merchant_id%22%3A%22m-1%22%2C%22amount%22%3A11%7D&MessageGroupId=m-1&MessageDeduplicationId=ord-test
Tue Apr 28 13:58:27 UTC 2026 : Sending request to arn:aws:apigateway:us-east-1:sqs:action/SendMessage
Tue Apr 28 13:58:27 UTC 2026 : Received response. Status: 400, Integration latency: 150 ms
Tue Apr 28 13:58:27 UTC 2026 : Endpoint response headers: {Server=TwistedWeb/24.3.0, Date=Tue, 28 Apr 2026 13:58:27 GMT, Content-Type=application/json, Content-Length=224, x-amzn-RequestId=cb5f0c6a-0822-4262-bf66-4b4ed8c2b934, x-localstack=true}
Tue Apr 28 13:58:27 UTC 2026 : Endpoint response body before transformations: {"ErrorResponse": {"Error": {"Code": "AWS.SimpleQueueService.NonExistentQueue", "Message": "The specified queue does not exist for this wsdl version.", "Type": "Sender"}, "RequestId": "cb5f0c6a-0822-4262-bf66-4b4ed8c2b934"}}
Tue Apr 28 13:58:27 UTC 2026 : Method response body after transformations: {"status":"queued"}
Tue Apr 28 13:58:27 UTC 2026 : Method response headers: {X-Amzn-Trace-Id=Root=1-69f0bd02-a86ead64f8f6f83077356161;Parent=5190dafa57ddfc66;Sampled=0, Content-Type=application/json}
Tue Apr 28 13:58:27 UTC 2026 : Successfully completed execution
Tue Apr 28 13:58:27 UTC 2026 : Method completed with status: 200Investigate raw SQS calls
# Let me understand what SQS endpoint accepts directly. Send a raw form POST and watch what works. echo "--- Test 1: form POST with QueueUrl param to root ---" curl -s -X POST 'http://sqs.us-east-1.localhost.localstack.cloud:4566/' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'Action=SendMessage&QueueUrl=http%3A%2F%2Fsqs.us-east-1.localhost.localstack.cloud%3A4566%2F000000000000%2Forders.fifo&MessageBody=hello&MessageGroupId=g1&MessageDeduplicationId=d1' | head -c 400 echo echo "--- Test 2: form POST to path /000000000000/orders.fifo ---" curl -s -X POST 'http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'Action=SendMessage&MessageBody=hello&MessageGroupId=g1&MessageDeduplicationId=d2' | head -c 400 echo echo "--- Test 3: form POST without explicit Content-Type ---" curl -s -X POST 'http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo' \ -d 'Action=SendMessage&MessageBody=hello&MessageGroupId=g1&MessageDeduplicationId=d3' | head -c 400 echo
--- Test 1: form POST with QueueUrl param to root --- --- Test 2: form POST to path /000000000000/orders.fifo --- --- Test 3: form POST without explicit Content-Type --- [stdout] --- Test 1: form POST with QueueUrl param to root --- --- Test 2: form POST to path /000000000000/orders.fifo --- --- Test 3: form POST without explicit Content-Type ---
Verbose curl to SQS
echo "--- Test verbose ---" curl -sv -X POST 'http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'Action=SendMessage&MessageBody=hello&MessageGroupId=g1&MessageDeduplicationId=raw1' 2>&1 | tail -25
--- Test verbose --- * Host sqs.us-east-1.localhost.localstack.cloud:4566 was resolved. * IPv6: (none) * IPv4: 127.0.0.1 * Trying 127.0.0.1:4566... * connect to 127.0.0.1 port 4566 from 127.0.0.1 port 44956 failed: Connection refused * Failed to connect to sqs.us-east-1.localhost.localstack.cloud port 4566 after 7 ms: Couldn't connect to server * Closing connection [stdout] --- Test verbose --- * Host sqs.us-east-1.localhost.localstack.cloud:4566 was resolved. * IPv6: (none) * IPv4: 127.0.0.1 * Trying 127.0.0.1:4566... * connect to 127.0.0.1 port 4566 from 127.0.0.1 port 44956 failed: Connection refused * Failed to connect to sqs.us-east-1.localhost.localstack.cloud port 4566 after 7 ms: Couldn't connect to server * Closing connection
Direct curl to localstack:4566 path style
echo "--- direct to localstack hostname ---" curl -sv -X POST 'http://localstack:4566/000000000000/orders.fifo' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'Action=SendMessage&MessageBody=hello&MessageGroupId=g1&MessageDeduplicationId=raw1' 2>&1 | tail -20
--- direct to localstack hostname ---
> POST /000000000000/orders.fifo HTTP/1.1
> Host: localstack:4566
> User-Agent: curl/8.5.0
> Accept: */*
> Content-Type: application/x-www-form-urlencoded
> Content-Length: 82
>
} [82 bytes data]
< HTTP/1.1 200 OK
< Server: TwistedWeb/24.3.0
< Date: Tue, 28 Apr 2026 13:58:48 GMT
< Content-Type: text/xml
< Content-Length: 449
< x-amzn-RequestId: ab3b7ca9-d967-476a-84e0-8f3906660e99
< x-localstack: true
<
{ [449 bytes data]
* Connection #0 to host localstack left intact
<?xml version='1.0' encoding='utf-8'?>
<SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><SendMessageResult><MD5OfMessageBody>5d41402abc4b2a76b9719d911017c592</MD5OfMessageBody><MessageId>4b1adcca-03b7-4eab-8703-86e953612dee</MessageId><SequenceNumber>15267617123820634113</SequenceNumber></SendMessageResult><ResponseMetadata><RequestId>ab3b7ca9-d967-476a-84e0-8f3906660e99</RequestId></ResponseMetadata></SendMessageResponse>
[stdout]
--- direct to localstack hostname ---
> POST /000000000000/orders.fifo HTTP/1.1
> Host: localstack:4566
> User-Agent: curl/8.5.0
> Accept: */*
> Content-Type: application/x-www-form-urlencoded
> Content-Length: 82
>
} [82 bytes data]
< HTTP/1.1 200 OK
< Server: TwistedWeb/24.3.0
< Date: Tue, 28 Apr 2026 13:58:48 GMT
< Content-Type: text/xml
< Content-Length: 449
< x-amzn-RequestId: ab3b7ca9-d967-476a-84e0-8f3906660e99
< x-localstack: true
<
{ [449 bytes data]
* Connection #0 to host localstack left intact
<?xml version='1.0' encoding='utf-8'?>
<SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><SendMessageResult><MD5OfMessageBody>5d41402abc4b2a76b9719d911017c592</MD5OfMessageBody><MessageId>4b1adcca-03b7-4eab-8703-86e953612dee</MessageId><SequenceNumber>15267617123820634113</SequenceNumber></SendMessageResult><ResponseMetadata><RequestId>ab3b7ca9-d967-476a-84e0-8f3906660e99</RequestId></ResponseMetadata></SendMessageResponse>Probe SQS root endpoint with QueueUrl variants
API_ID=$(cat /tmp/build/api_id)
RES_ID=$(cat /tmp/build/res_id)
# Try various QueueUrl formats by directly sending HTTP and seeing what SQS' root endpoint accepts
for QU in 'orders.fifo' '000000000000%2Forders.fifo' '%2F000000000000%2Forders.fifo' 'http%3A%2F%2Flocalstack%3A4566%2F000000000000%2Forders.fifo'; do
echo "--- QueueUrl=$QU ---"
curl -s -X POST 'http://localstack:4566/' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d "Action=SendMessage&QueueUrl=$QU&MessageBody=hi&MessageGroupId=g&MessageDeduplicationId=d-$RANDOM" | head -c 300
echo
done--- QueueUrl=orders.fifo --- <?xml version='1.0' encoding='utf-8'?> <SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><SendMessageResult><MessageId>9bd6acb8-dc01-4e67-b944-71b8635b730e</MessageId><MD5OfMessageBody>49f68a5c8493ec2c0bf489821c21fc3b</MD5OfMessageBody><SequenceNumber>15267617123820634114</Sequ --- QueueUrl=000000000000%2Forders.fifo --- <?xml version='1.0' encoding='utf-8'?> <SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><SendMessageResult><MessageId>2e0ead7a-9553-46d5-83d2-c78c764f285c</MessageId><MD5OfMessageBody>49f68a5c8493ec2c0bf489821c21fc3b</MD5OfMessageBody><SequenceNumber>15267617123820634115</Sequ --- QueueUrl=%2F000000000000%2Forders.fifo --- <?xml version='1.0' encoding='utf-8'?> <SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><SendMessageResult><MessageId>e3bbb013-8b19-45a8-9fe0-48480f0d83c0</MessageId><MD5OfMessageBody>49f68a5c8493ec2c0bf489821c21fc3b</MD5OfMessageBody><SequenceNumber>15267617123820634116</Sequ --- QueueUrl=http%3A%2F%2Flocalstack%3A4566%2F000000000000%2Forders.fifo --- <?xml version='1.0' encoding='utf-8'?> <SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><SendMessageResult><MessageId>fc72dc32-0266-416f-9203-5f7625cc7f4a</MessageId><MD5OfMessageBody>49f68a5c8493ec2c0bf489821c21fc3b</MD5OfMessageBody><SequenceNumber>15267617123820634117</Sequ [stdout] --- QueueUrl=orders.fifo --- <?xml version='1.0' encoding='utf-8'?> <SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><SendMessageResult><MessageId>9bd6acb8-dc01-4e67-b944-71b8635b730e</MessageId><MD5OfMessageBody>49f68a5c8493ec2c0bf489821c21fc3b</MD5OfMessageBody><SequenceNumber>15267617123820634114</Sequ --- QueueUrl=000000000000%2Forders.fifo --- <?xml version='1.0' encoding='utf-8'?> <SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><SendMessageResult><MessageId>2e0ead7a-9553-46d5-83d2-c78c764f285c</MessageId><MD5OfMessageBody>49f68a5c8493ec2c0bf489821c21fc3b</MD5OfMessageBody><SequenceNumber>15267617123820634115</Sequ --- QueueUrl=%2F000000000000%2Forders.fifo --- <?xml version='1.0' encoding='utf-8'?> <SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><SendMessageResult><MessageId>e3bbb013-8b19-45a8-9fe0-48480f0d83c0</MessageId><MD5OfMessageBody>49f68a5c8493ec2c0bf489821c21fc3b</MD5OfMessageBody><SequenceNumber>15267617123820634116</Sequ --- QueueUrl=http%3A%2F%2Flocalstack%3A4566%2F000000000000%2Forders.fifo --- <?xml version='1.0' encoding='utf-8'?> <SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><SendMessageResult><MessageId>fc72dc32-0266-416f-9203-5f7625cc7f4a</MessageId><MD5OfMessageBody>49f68a5c8493ec2c0bf489821c21fc3b</MD5OfMessageBody><SequenceNumber>15267617123820634117</Sequ
Inspect integration request parameters
API_ID=$(cat /tmp/build/api_id) RES_ID=$(cat /tmp/build/res_id) aws apigateway get-integration --rest-api-id "$API_ID" --resource-id "$RES_ID" --http-method POST --query '[uri,requestParameters]' --output json
[
"arn:aws:apigateway:us-east-1:sqs:action/SendMessage",
{
"integration.request.header.Content-Type": "application/x-www-form-urlencoded"
}
]
[stdout]
[
"arn:aws:apigateway:us-east-1:sqs:action/SendMessage",
{
"integration.request.header.Content-Type": "application/x-www-form-urlencoded"
}
]Set Content-Type with single-quoted literal
API_ID=$(cat /tmp/build/api_id)
RES_ID=$(cat /tmp/build/res_id)
# Re-set with proper single-quoted literal value
python3 - <<PY > /tmp/build/patch.json
import json
print(json.dumps({
"restApiId": "$API_ID",
"resourceId": "$RES_ID",
"httpMethod": "POST",
"patchOperations": [
{"op":"replace","path":"/requestParameters/integration.request.header.Content-Type","value":"'application/x-www-form-urlencoded'"}
]
}))
PY
aws apigateway update-integration --cli-input-json file:///tmp/build/patch.json --query 'requestParameters' --output json
aws apigateway create-deployment --rest-api-id "$API_ID" --stage-name dev --query id --output text
aws apigateway test-invoke-method \
--rest-api-id "$API_ID" \
--resource-id "$RES_ID" \
--http-method POST \
--headers Content-Type=application/json \
--body '{"order_id":"ord-x","merchant_id":"m-1","amount":11}' --query 'log' --output text 2>&1 | tail -8{
"integration.request.header.Content-Type": "'application/x-www-form-urlencoded'"
}
5hujdvi7ba
Tue Apr 28 13:59:32 UTC 2026 : Received response. Status: 200, Integration latency: 150 ms
Tue Apr 28 13:59:32 UTC 2026 : Endpoint response headers: {Server=TwistedWeb/24.3.0, Date=Tue, 28 Apr 2026 13:59:32 GMT, Content-Type=application/json, Content-Length=274, x-amzn-RequestId=a4678a70-1575-4a0d-9d5a-005ee9af4542, x-localstack=true}
Tue Apr 28 13:59:32 UTC 2026 : Endpoint response body before transformations: {"SendMessageResponse": {"SendMessageResult": {"MessageId": "50f8b17d-c5a0-4178-90c0-843a9c8030c0", "MD5OfMessageBody": "c38ba09e395c4af708718992d18e1065", "SequenceNumber": "15267617123820634118"}, "ResponseMetadata": {"RequestId": "a4678a70-1575-4a0d-9d5a-005ee9af4542"}}}
Tue Apr 28 13:59:32 UTC 2026 : Method response body after transformations: {"status":"queued"}
Tue Apr 28 13:59:32 UTC 2026 : Method response headers: {X-Amzn-Trace-Id=Root=1-69f0bd44-c98799aa95059bdfb4ee7323;Parent=77bd38c5a50450f5;Sampled=0, Content-Type=application/json}
Tue Apr 28 13:59:32 UTC 2026 : Successfully completed execution
Tue Apr 28 13:59:32 UTC 2026 : Method completed with status: 200
[stdout]
{
"integration.request.header.Content-Type": "'application/x-www-form-urlencoded'"
}
5hujdvi7ba
Tue Apr 28 13:59:32 UTC 2026 : Received response. Status: 200, Integration latency: 150 ms
Tue Apr 28 13:59:32 UTC 2026 : Endpoint response headers: {Server=TwistedWeb/24.3.0, Date=Tue, 28 Apr 2026 13:59:32 GMT, Content-Type=application/json, Content-Length=274, x-amzn-RequestId=a4678a70-1575-4a0d-9d5a-005ee9af4542, x-localstack=true}
Tue Apr 28 13:59:32 UTC 2026 : Endpoint response body before transformations: {"SendMessageResponse": {"SendMessageResult": {"MessageId": "50f8b17d-c5a0-4178-90c0-843a9c8030c0", "MD5OfMessageBody": "c38ba09e395c4af708718992d18e1065", "SequenceNumber": "15267617123820634118"}, "ResponseMetadata": {"RequestId": "a4678a70-1575-4a0d-9d5a-005ee9af4542"}}}
Tue Apr 28 13:59:32 UTC 2026 : Method response body after transformations: {"status":"queued"}
Tue Apr 28 13:59:32 UTC 2026 : Method response headers: {X-Amzn-Trace-Id=Root=1-69f0bd44-c98799aa95059bdfb4ee7323;Parent=77bd38c5a50450f5;Sampled=0, Content-Type=application/json}
Tue Apr 28 13:59:32 UTC 2026 : Successfully completed execution
Tue Apr 28 13:59:32 UTC 2026 : Method completed with status: 200Clean DDB and queues
# Clean DDB
aws dynamodb scan --table-name orders --query 'Items[*].order_id.S' --output text | tr '\t' '\n' | while read id; do
[ -n "$id" ] && aws dynamodb delete-item --table-name orders --key "{\"order_id\":{\"S\":\"$id\"}}"
done
# Drain the queues
aws sqs purge-queue --queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo 2>&1 | head -2
aws sqs purge-queue --queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders-dlq.fifo 2>&1 | head -2
sleep 2
echo "--- ddb after clean ---"
aws dynamodb scan --table-name orders --query Items
echo "--- main queue ---"
aws sqs get-queue-attributes --queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo --attribute-names ApproximateNumberOfMessages --query 'Attributes.ApproximateNumberOfMessages' --output text
echo "--- dlq ---"
aws sqs get-queue-attributes --queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders-dlq.fifo --attribute-names ApproximateNumberOfMessages --query 'Attributes.ApproximateNumberOfMessages' --output text--- ddb after clean --- [] --- main queue --- 0 --- dlq --- 0 [stdout] --- ddb after clean --- [] --- main queue --- 0 --- dlq --- 0
E2E POST and verify DDB has the row
API_ID=$(cat /tmp/build/api_id)
URL="http://localstack:4566/restapis/${API_ID}/dev/_user_request_/orders"
echo "URL=$URL"
echo "--- POST ord-1 ---"
curl -s -o /tmp/build/r.json -w "HTTP %{http_code}\n" -X POST "$URL" -H 'Content-Type: application/json' \
-d '{"order_id":"ord-1","merchant_id":"m-A","amount":100}'
cat /tmp/build/r.json; echo
sleep 5
echo "--- ddb ---"
aws dynamodb scan --table-name orders --output json | jq '.Items'
echo "--- main q ---"
aws sqs get-queue-attributes --queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo --attribute-names ApproximateNumberOfMessages --query 'Attributes.ApproximateNumberOfMessages' --output text
echo "--- dlq ---"
aws sqs get-queue-attributes --queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders-dlq.fifo --attribute-names ApproximateNumberOfMessages --query 'Attributes.ApproximateNumberOfMessages' --output textURL=http://localstack:4566/restapis/ydphp7gmv3/dev/_user_request_/orders
--- POST ord-1 ---
HTTP 200
{"status":"queued"}
--- ddb ---
[]
--- main q ---
1
--- dlq ---
0
[stdout]
URL=http://localstack:4566/restapis/ydphp7gmv3/dev/_user_request_/orders
--- POST ord-1 ---
HTTP 200
{"status":"queued"}
--- ddb ---
[]
--- main q ---
1
--- dlq ---
0Poll until consumer picks up
for i in 1 2 3 4 5 6 7 8; do Q=$(aws sqs get-queue-attributes --queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders.fifo --attribute-names ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible --query 'Attributes' --output json | tr -d ' \n') N=$(aws dynamodb scan --table-name orders --query 'Count' --output text) echo "[$i] q=$Q ddb_rows=$N" sleep 2 done aws dynamodb scan --table-name orders --output json | jq '.Items'
[1] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[2] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[3] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[4] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[5] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[6] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[7] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[8] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[
{
"created_at": {
"N": "1777384802957"
},
"amount": {
"N": "100"
},
"merchant_id": {
"S": "m-A"
},
"order_id": {
"S": "ord-1"
}
}
]
[stdout]
[1] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[2] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[3] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[4] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[5] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[6] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[7] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[8] q={"ApproximateNumberOfMessages":"0","ApproximateNumberOfMessagesNotVisible":"0"} ddb_rows=1
[
{
"created_at": {
"N": "1777384802957"
},
"amount": {
"N": "100"
},
"merchant_id": {
"S": "m-A"
},
"order_id": {
"S": "ord-1"
}
}
]Idempotency test
API_ID=$(cat /tmp/build/api_id)
URL="http://localstack:4566/restapis/${API_ID}/dev/_user_request_/orders"
ORIG_CREATED=$(aws dynamodb get-item --table-name orders --key '{"order_id":{"S":"ord-1"}}' --query 'Item.created_at.N' --output text)
echo "original created_at = $ORIG_CREATED"
echo "--- Re-POST same body (dedup test) ---"
curl -s -o /tmp/build/r.json -w "HTTP %{http_code}\n" -X POST "$URL" -H 'Content-Type: application/json' \
-d '{"order_id":"ord-1","merchant_id":"m-A","amount":100}'
cat /tmp/build/r.json; echo
# Wait for ESM to process (or for SQS to dedup-drop within the FIFO 5min window)
sleep 8
echo "--- ddb after re-POST ---"
aws dynamodb scan --table-name orders --output json | jq '.Items'
NEW_CREATED=$(aws dynamodb get-item --table-name orders --key '{"order_id":{"S":"ord-1"}}' --query 'Item.created_at.N' --output text)
echo "after re-POST created_at = $NEW_CREATED (orig=$ORIG_CREATED)"
[ "$ORIG_CREATED" = "$NEW_CREATED" ] && echo "OK: row unchanged" || echo "FAIL: row changed"
echo "--- count ---"
aws dynamodb scan --table-name orders --query 'Count' --output text
echo "--- dlq ---"
aws sqs get-queue-attributes --queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders-dlq.fifo --attribute-names ApproximateNumberOfMessages --query 'Attributes.ApproximateNumberOfMessages' --output textoriginal created_at = 1777384802957
--- Re-POST same body (dedup test) ---
HTTP 200
{"status":"queued"}
--- ddb after re-POST ---
[
{
"created_at": {
"N": "1777384802957"
},
"amount": {
"N": "100"
},
"merchant_id": {
"S": "m-A"
},
"order_id": {
"S": "ord-1"
}
}
]
after re-POST created_at = 1777384802957 (orig=1777384802957)
OK: row unchanged
--- count ---
1
--- dlq ---
0
[stdout]
original created_at = 1777384802957
--- Re-POST same body (dedup test) ---
HTTP 200
{"status":"queued"}
--- ddb after re-POST ---
[
{
"created_at": {
"N": "1777384802957"
},
"amount": {
"N": "100"
},
"merchant_id": {
"S": "m-A"
},
"order_id": {
"S": "ord-1"
}
}
]
after re-POST created_at = 1777384802957 (orig=1777384802957)
OK: row unchanged
--- count ---
1
--- dlq ---
0Order preservation test
API_ID=$(cat /tmp/build/api_id)
URL="http://localstack:4566/restapis/${API_ID}/dev/_user_request_/orders"
echo "--- POST ord-2 then ord-3 same merchant ---"
curl -s -o /dev/null -w "ord-2 HTTP %{http_code}\n" -X POST "$URL" -H 'Content-Type: application/json' \
-d '{"order_id":"ord-2","merchant_id":"m-A","amount":222}'
sleep 1
curl -s -o /dev/null -w "ord-3 HTTP %{http_code}\n" -X POST "$URL" -H 'Content-Type: application/json' \
-d '{"order_id":"ord-3","merchant_id":"m-A","amount":333}'
# wait
for i in 1 2 3 4 5 6 7 8 9 10; do
N=$(aws dynamodb scan --table-name orders --query 'Count' --output text)
echo "[$i] ddb_rows=$N"
[ "$N" = "3" ] && break
sleep 2
done
echo "--- All rows ---"
aws dynamodb scan --table-name orders --output json | jq '.Items | sort_by(.created_at.N | tonumber)'
echo "--- DLQ ---"
aws sqs get-queue-attributes --queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/orders-dlq.fifo --attribute-names ApproximateNumberOfMessages --query 'Attributes.ApproximateNumberOfMessages' --output text--- POST ord-2 then ord-3 same merchant ---
ord-2 HTTP 200
ord-3 HTTP 200
[1] ddb_rows=1
[2] ddb_rows=1
[3] ddb_rows=1
[4] ddb_rows=3
--- All rows ---
[
{
"created_at": {
"N": "1777384802957"
},
"amount": {
"N": "100"
},
"merchant_id": {
"S": "m-A"
},
"order_id": {
"S": "ord-1"
}
},
{
"created_at": {
"N": "1777384867145"
},
"amount": {
"N": "222"
},
"merchant_id": {
"S": "m-A"
},
"order_id": {
"S": "ord-2"
}
},
{
"created_at": {
"N": "1777384867208"
},
"amount": {
"N": "333"
},
"merchant_id": {
"S": "m-A"
},
"order_id": {
"S": "ord-3"
}
}
]
--- DLQ ---
0
[stdout]
--- POST ord-2 then ord-3 same merchant ---
ord-2 HTTP 200
ord-3 HTTP 200
[1] ddb_rows=1
[2] ddb_rows=1
[3] ddb_rows=1
[4] ddb_rows=3
--- All rows ---
[
{
"created_at": {
"N": "1777384802957"
},
"amount": {
"N": "100"
},
"merchant_id": {
"S": "m-A"
},
"order_id": {
"S": "ord-1"
}
},
{
"created_at": {
"N": "1777384867145"
},
"amount": {
"N": "222"
},
"merchant_id": {
"S": "m-A"
},
"order_id": {
"S": "ord-2"
}
},
{
"created_at": {
"N": "1777384867208"
},
"amount": {
"N": "333"
},
"merchant_id": {
"S": "m-A"
},
"order_id": {
"S": "ord-3"
}
}
]
--- DLQ ---
0No file changes, the agent left the workspace untouched.
============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-8.4.1, pluggy-1.6.0 -- /root/.cache/uv/archive-v0/ymJyrJiYDS5DrPIxwkgp5/bin/python
cachedir: .pytest_cache
rootdir: /tests
plugins: json-ctrf-0.3.5
collecting ... collected 19 items
../tests/test_outputs.py::test_localstack_reachable PASSED [ 5%]
../tests/test_outputs.py::test_main_fifo_queue_exists PASSED [ 10%]
../tests/test_outputs.py::test_dlq_fifo_queue_exists PASSED [ 15%]
../tests/test_outputs.py::test_ddb_table_exists PASSED [ 21%]
../tests/test_outputs.py::test_lambda_and_esm_exist PASSED [ 26%]
../tests/test_outputs.py::test_rest_api_exists_with_post_orders PASSED [ 31%]
../tests/test_outputs.py::test_integration_uri_targets_fifo_queue FAILED [ 36%]
../tests/test_outputs.py::test_integration_credentials_role_is_set PASSED [ 42%]
../tests/test_outputs.py::test_integration_sets_content_type_header PASSED [ 47%]
../tests/test_outputs.py::test_integration_request_template_uses_full_body PASSED [ 52%]
../tests/test_outputs.py::test_integration_request_template_has_message_group_id PASSED [ 57%]
../tests/test_outputs.py::test_integration_request_template_has_dedup_id PASSED [ 63%]
../tests/test_outputs.py::test_integration_template_identifiers_are_request_derived PASSED [ 68%]
../tests/test_outputs.py::test_stage_deployment_id_was_refreshed PASSED [ 73%]
../tests/test_outputs.py::test_event_source_mapping_declares_report_batch_item_failures PASSED [ 78%]
../tests/test_outputs.py::test_lambda_handler_idempotency_and_response_shape PASSED [ 84%]
../tests/test_outputs.py::test_end_to_end_post_reaches_ddb_no_dlq PASSED [ 89%]
../tests/test_outputs.py::test_end_to_end_fifo_group_ordering PASSED [ 94%]
../tests/test_outputs.py::test_end_to_end_duplicate_post_is_idempotent PASSED [100%]
=================================== FAILURES ===================================
___________________ test_integration_uri_targets_fifo_queue ____________________
apigw = <botocore.client.APIGateway object at 0xffff80995460>
def test_integration_uri_targets_fifo_queue(apigw):
"""Integration targets FIFO."""
_api, _res, integ = _integration(apigw)
uri = integ.get("uri", "")
> assert uri.endswith(f"/{MAIN_QUEUE}") or uri.endswith(
f":path/{ACCOUNT_ID}/{MAIN_QUEUE}"
), (
f"integration URI {uri!r} does not target the FIFO queue "
f"{MAIN_QUEUE}. A FIFO queue name always ends in `.fifo`; if "
f"the URI path ends in `orders` (without `.fifo`) the send "
f"will silently fail."
)
E AssertionError: integration URI 'arn:aws:apigateway:us-east-1:sqs:action/SendMessage' does not target the FIFO queue orders.fifo. A FIFO queue name always ends in `.fifo`; if the URI path ends in `orders` (without `.fifo`) the send will silently fail.
E assert (False or False)
E + where False = <built-in method endswith of str object at 0xffff809e4e10>('/orders.fifo')
E + where <built-in method endswith of str object at 0xffff809e4e10> = 'arn:aws:apigateway:us-east-1:sqs:action/SendMessage'.endswith
E + and False = <built-in method endswith of str object at 0xffff809e4e10>(':path/000000000000/orders.fifo')
E + where <built-in method endswith of str object at 0xffff809e4e10> = 'arn:aws:apigateway:us-east-1:sqs:action/SendMessage'.endswith
/tests/test_outputs.py:200: AssertionError
=============================== warnings summary ===============================
test_outputs.py: 64 warnings
/root/.cache/uv/archive-v0/ymJyrJiYDS5DrPIxwkgp5/lib/python3.12/site-packages/botocore/auth.py:424: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
datetime_now = datetime.datetime.utcnow()
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
==================================== PASSES ====================================
=========================== short test summary info ============================
PASSED ../tests/test_outputs.py::test_localstack_reachable
PASSED ../tests/test_outputs.py::test_main_fifo_queue_exists
PASSED ../tests/test_outputs.py::test_dlq_fifo_queue_exists
PASSED ../tests/test_outputs.py::test_ddb_table_exists
PASSED ../tests/test_outputs.py::test_lambda_and_esm_exist
PASSED ../tests/test_outputs.py::test_rest_api_exists_with_post_orders
PASSED ../tests/test_outputs.py::test_integration_credentials_role_is_set
PASSED ../tests/test_outputs.py::test_integration_sets_content_type_header
PASSED ../tests/test_outputs.py::test_integration_request_template_uses_full_body
PASSED ../tests/test_outputs.py::test_integration_request_template_has_message_group_id
PASSED ../tests/test_outputs.py::test_integration_request_template_has_dedup_id
PASSED ../tests/test_outputs.py::test_integration_template_identifiers_are_request_derived
PASSED ../tests/test_outputs.py::test_stage_deployment_id_was_refreshed
PASSED ../tests/test_outputs.py::test_event_source_mapping_declares_report_batch_item_failures
PASSED ../tests/test_outputs.py::test_lambda_handler_idempotency_and_response_shape
PASSED ../tests/test_outputs.py::test_end_to_end_post_reaches_ddb_no_dlq
PASSED ../tests/test_outputs.py::test_end_to_end_fifo_group_ordering
PASSED ../tests/test_outputs.py::test_end_to_end_duplicate_post_is_idempotent
FAILED ../tests/test_outputs.py::test_integration_uri_targets_fifo_queue - As...
================== 1 failed, 18 passed, 64 warnings in 22.74s ==================Reproduce this trial: git checkout 2f94510 && PYTHONPATH=src python3 scripts/build_site.py , then open trial/trial_e34bc6697df745f6. Re-running the agent live requires EVAL_PLATFORM_ENABLE_OAUTH_SMOKE=1 and is non-deterministic.
Trial trial_e34bc6697df745f6 · verifier authoritative; classifier explanatory.