cd /news/artificial-intelligence/how-i-solved-claude-code-silently-mi… · home topics artificial-intelligence article
[ARTICLE · art-69140] src=dev.to ↗ pub= topic=artificial-intelligence verified=true sentiment=· neutral

How I Solved Claude Code Silently Missing the SQS Trigger on My Lambda

A developer detailed how Claude Code silently introduced a bug by guessing the event shape for an SQS-triggered Lambda, accessing `event.body` instead of the correct `event.Records[0].body`. The developer then used the Infrawise MCP server to provide Claude Code with accurate infrastructure context—trigger type, queue details, and table schema—eliminating guesswork and catching issues like missing dead-letter queues before deployment.

read5 min views1 publishedJul 22, 2026

I asked Claude Code to add a handler for processOrders

, a Lambda wired up to consume from orders-queue

and read the matching row out of the Orders

DynamoDB table. It wrote one immediately — confidently, in one shot, the way it writes most things.

It also parsed the event body wrong.

processOrders

is invoked by orders-queue

through an event source mapping — that's not in processOrders

's source file, it's in the AWS account. Claude Code, reading only the handler's code, had no way to see that mapping. So it guessed at the event shape instead of knowing it, and reached for event.body

— the shape you'd expect from an API Gateway proxy integration, not from SQS. The actual shape for an SQS-triggered Lambda is event.Records[0].body

. First message in, first field access, and the handler throws.

That wasn't the only thing invisible from source alone:

orders-queue

has no dead-letter queue. If the handler throws, SQS retries up to maxReceiveCount

times and then discards the message — no alert, no queue-depth spike, nothing in the logs pointing at what happened. A failed order just vanishes.Orders

table has one partition key (orderId

) and zero GSIs. Any lookup by anything else becomes a full table scan the moment the handler ships.None of that is visible from reading processOrders

's current code. It's the state of the AWS account, and an AI assistant reading only source files fills the gap with a plausible guess instead of a fact — starting with which trigger the function even has.

Here's what the same session looked like once I wired infrawise into Claude Code as an MCP server and asked it to redo the handler.

Start wide: get_infra_overview. No arguments, just a snapshot — table names, queue names, lambda count, high-severity findings. It comes back showing the

Orders

table, orders-queue

, and processOrders

already in the graph, plus a high-severity finding already attached to that Lambda. That finding surfaces before the handler is written, not after the deploy.Narrow to the function: analyze_function. Called with

function: "processOrders"

, this is the tool built for "I'm about to write or review this handler," and it returns four things Claude Code would otherwise guess at:processOrders

is triggered by SQS, so the correct shape is event.Records[0].body

— not event.body

. Infrawise keeps a fixed map per trigger type (SNS is event.Records[0].Sns.Message

, S3 is event.Records[0].s3.object.key

, DynamoDB Streams is event.Records[0].dynamodb.NewImage

), so the entry point is right on the first draft.LambdaMissingTriggerDLQAnalyzer

walks every Lambda's SQS/Kinesis/DynamoDB-stream triggers, checks whether the source queue has a DLQ, and raises high severity when it doesn't: analyze_function

diffs what the function's code actually calls against what its role allows, and returns the gap — catching an AccessDeniedException

before it happens in prod instead of after.Confirm the queue directly: get_queue_details. The handler's retry behavior depends on more than DLQ presence, so Claude Code checks the queue itself:

hasDLQ: false

confirmed, plus visibility timeout, encryption, and isFifo

. That last field matters more than it looks — if the queue were FIFO, every SendMessage

call in the handler would need a MessageGroupId

, and skipping it isn't a lint warning, it's a runtime error the first time the handler publishes.Get the schema right: get_table_schema. Called with

tables: ["Orders"] , this returns the partition key (orderId

), billing mode (PAY_PER_REQUEST ), and the fact that there are no GSIs. If the handler needs to look up an order by anything other than orderId

, that's a Scan

, and infrawise's scan analyzer flags it the moment it lands in the code graph — so Claude Code reaches for suggest_gsi

up front instead of shipping the scan and fixing it in the next PR. Row data is never included — column names, types, keys, and index definitions only, and only for the tables this handler actually touches, not the whole account's schema dumped into the prompt.With all four calls back, the rewritten handler:

event.Records[0].body — the correct shape for this trigger, not a guessOrders

by orderId

— no scan, because the schema call already ruled that outorders-queue

needs a DLQ before this goes to productionisFifo

firstEvery one of those four things was either wrong or invisible in the first version — the one Claude Code wrote from source files alone. None of it required me to open the AWS console mid-task or remember which table has which GSI.

The four tools compose in a fixed order because each answers a narrower question than the last: get_infra_overview

says what exists, analyze_function

says what's wrong with the one thing being touched, get_queue_details

and get_table_schema

fill in the operational and schema detail neither of the first two carries at full resolution. That's the same shape as infrawise's own "reviewing an entire service" and "before writing a query" patterns — it holds for any handler, not just this one.

None of this runs an LLM against the infrastructure. Extraction and analysis are deterministic — AST parsing, live AWS reads, rule-based analyzers, graph correlation. Claude Code only consumes that graph through MCP, the same way it consumes source files. The difference is the graph doesn't guess.

Try it in your own project — npx infrawise start --claude writes the .mcp.json

and opens Claude Code with all 21 tools wired in, no server to babysit. GitHub · npm analyze_function

before writing or reviewing any Lambda handler — it returns the correct trigger event shape, missing IAM permissions, and any DLQ/trigger findings in one call.maxReceiveCount

times, then discarded with no record.isFifo

on any queue before writing SendMessage

calls — a missing MessageGroupId

on a FIFO queue is a runtime error, not a style issue.get_table_schema

with just the tables a handler touches instead of dumping the whole schema into the prompt — it also tells you whether the GSI your query needs already exists.

── more in #artificial-intelligence 4 stories · sorted by recency
── more on @claude code 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/how-i-solved-claude-…] indexed:0 read:5min 2026-07-22 ·