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. 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 https://github.com/Sidd27/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 guess Orders by orderId — no scan, because the schema call already ruled that out orders-queue needs a DLQ before this goes to production isFifo 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 https://github.com/Sidd27/infrawise · npm https://www.npmjs.com/package/infrawise 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.