AI coding tools write for a world where every request arrives exactly one time, and production never works that way.
The Details:
Training data skews toward tutorials and clean examples, so models learn the straight path from input to output: parse the payload, charge the card, save the row, respond. They rarely see the retry queue, the timed-out load balancer, or the backfill job that replays a day's worth of events months later, so that context never shapes the code they produce.
Idempotency is a property of the whole system, not a function in isolation. A webhook handler can look flawless in isolation and still double-charge a customer once a message bus redelivers an event, because the database, the client's retry policy, and the handler all have to agree on what "already happened" means.
The fix is a prompting habit: state the invariant before asking for the behavior. Instead of "write a payment handler," specify "exactly one charge per order, even if this runs five times." That single sentence pushes the model toward an idempotency key, a unique constraint, or a transaction check instead of a bare happy path.
The defenses are ordinary, not exotic. A unique index on event ID plus operation type blocks duplicate rows at the database layer regardless of what the application code does. Pairing a state change with its outgoing message in one transaction, the transactional outbox pattern, prevents the classic failure where a service updates its record but crashes before publishing the event.
Bottom Line: AI tools execute the specification you give them with precision; when that specification omits what happens on a second try, the gap shows up in production, not in the pull request.
Enjoy this article?
Listen to the Claude Code Conversations radio show or join the community.