Build1 distinct publisher3 min readUpdated
A correct-looking batchItemFailures handler is inert unless the event source mapping agrees. One dev.to write-up grades the code-versus-mapping mismatch higher than the missing setting, and says why.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
The grading is the part worth stealing. A mapping with a batch size above 1 and no ReportBatchItemFailures is scored medium in the author's scanner, because the handler may genuinely not need per-record reporting, and a batch of one is skipped outright since it has nothing to partially fail [10]. The mismatch, where the code builds a batchItemFailures array and the mapping has the setting off, is scored high [11]. The analyzer description is blunt about the reason: "The code reads as correct and its unit tests pass; only the mapping tells the truth" [12]. The distinction being drawn is between an absence and an active false belief [16]. Somebody wrote that array on purpose, and whatever they concluded about idempotency downstream was concluded on the assumption that the nine good records would be deleted.
That assumption fails quietly. One throwing record sends the whole batch back, the nine that already ran to completion included, and it keeps replaying until the queue's retry limit [5]. Nine of ten records in each replay are re-executions, which puts 90 percent of the retried work in the duplicate column [1]. If the handler is not idempotent, the author's phrasing is fair: double-charged customers rather than a log line [6]. A unit test that feeds ten records and asserts one entry in the failure array passes the entire time [7].
Neither side of the check is expensive, which is the uncomfortable bit. Both scanners match a name: ts-morph on a property or shorthand property called batchItemFailures, the Python scanner on the same dict key, with no control-flow tracing to a return statement, on the reasoning that an array by that name has no other purpose in a Lambda handler [13]. The infrastructure side is close to free, because FunctionResponseTypes already arrives on the ListEventSourceMappings response that trigger extraction pages through anyway [14]. So this class of defect does not survive because it is hard to find. It survives because the two halves are never in the same place: a Terraform module in another repo, a CDK stack another team owns, or a checkbox someone clicked in a console eighteen months ago, none of which your editor or test suite can see [8].
One design choice deserves reading closely. Both checks fire only on an explicit false [15]. The write-up's explanation of that rule breaks off mid-comment in the material supplied, so how an unreadable or absent mapping is treated is not stated. Either way, a finding means the two halves disagree, and silence cannot be read as agreement.
Then the assistant path, which is how the high-severity direction gets manufactured at volume. Asked to add partial batch failure handling to a consumer, an assistant writes exactly the correct-looking handler and reports the job done, not hallucinating, just writing the only half it can see [9]. The cheap half to generate is the half that is graded high when it is wrong. On that basis the mismatch population should grow faster than the plain-absence population, and it will grow in repositories where the mapping is owned by someone who was never in the pull request.
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
In a comment on the author's earlier post about an AI assistant missing an SQS trigger on a Lambda, Mads Hansen said the trigger shape is the first contract and delivery and retry semantics are the second.
The example handler loops over event.Records, catches per record rather than around the loop, pushes record.messageId as itemIdentifier, and returns { batchItemFailures }.
Whether Lambda honours the returned batchItemFailures array is decided by the event source mapping: if FunctionResponseTypes on the mapping does not contain ReportBatchItemFailures, Lambda discards the array and marks the whole batch failed.
With the setting off, all ten records are redelivered including the nine that already ran to completion, and one poison message keeps replaying its batch until the queue's retry limit; the failure mode is duplicate processing.
If the handler is not idempotent, the result is double-charged customers, not a log line.
A unit test that feeds the handler ten records and asserts one entry in batchItemFailures passes.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
One self-reported practitioner account of a checkable platform behaviour
The core mechanism — Lambda discarding a batchItemFailures array unless FunctionResponseTypes on the event source mapping contains ReportBatchItemFailures, causing full-batch redelivery — is stated precisely enough to verify against platform behaviour, and the article supplies a code sample, the analyzer conditions, and the actual guard clause. But the cluster contains exactly one source, written by the author of the tool being described, with no independent confirmation, no measured false-positive rate for name-only batchItemFailures matching, and a body that is truncated mid-sentence on the mapping-side conclusion.
Vendor-side shipping only, no third-party usage
The only adoption facts supplied are the author's own release details: two analyzers in Infrawise, mapping fields carried into analyze_function and get_lambda_overview, and a build failure at the default --fail-on high. There are no users, installs, customer accounts, benchmark runs, or reports of the check firing in someone else's infrastructure, so adoption is limited to first-party availability.
Mildly overstated on tooling, sober on mechanism
The failure mechanism and its consequence are argued conservatively and with self-imposed limits: the missing-setting finding is graded only medium, batches of one are skipped, and the author refuses to flag an undefined field because a tool that accuses wrongly gets muted. That restraint keeps the gap small. It is positive rather than zero because the efficacy of a name-matching detector and the claimed universality of the AI-assistant failure ('writes exactly the handler above') are asserted without any measurement, while the piece simultaneously recommends the author's own product.
Author markets the tool that solves the problem he describes
The write-up is a product narrative: it defines a defect class no reviewer or test can catch, then presents the author's own tool Infrawise, its two analyzers, its severity grading, its MCP-style tool fields, and its build-failing CLI as the answer. That is a direct commercial and reputational incentive to make the defect sound both common and hard to see, and it is not disclosed as a vendor post. The incentive is partly offset by the author publishing his tool's blind spots (name matching only, undefined-versus-false, partial extraction) rather than hiding them.
Mechanism credible, tooling and reach unverified
Confidence is moderate: the technical claim chain is internally consistent, code-level, and specific enough to check independently, and the author volunteers the limits of his own detector. It is held down by single-source, single-publisher coverage, a self-interested narrator, zero third-party adoption or outcome data, and a supplied body that cuts off before the mapping-side conclusion is finished.
build
Two mechanisms, one vCPU floor: why db.t3.micro cannot meet a 1-second RPO on RDS1 distinct publisher
build
Two NAT Gateways nobody asked for: review cloud bills at 100x, not at this month1 distinct publisher
build
A batch job that returns false on failure makes your CloudWatch alarm decorative1 distinct publisher
build
DynamoDB vector indexes remove the second datastore, and the GSI permutation trap with it1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 24, 2026