Ignoring Idempotency
Ignoring idempotency lets retries cause duplicate effects like double charges and duplicate records. Use idempotent HTTP methods, support idempotency keys for creates, and deduplicate on business keys so retries are always safe.
Ignoring idempotency means designing operations — especially writes — that produce different effects when invoked more than once. In a distributed world where requests time out and clients retry, the same request can arrive twice, and a non-idempotent design turns that into duplicate side effects.
Why It Happens
It is easy to forget that the network is unreliable. A POST creates a record; the developer assumes it runs once. But a client that doesn't receive a response cannot know whether the request succeeded, so it retries — and the server creates a second record. Teams often design for the happy path where every request gets exactly one response, ignoring the at-least-once reality of timeouts, proxies, and load balancers that retry.
Why It Hurts
Without idempotency, retries — which are unavoidable — cause real damage: duplicate orders, double charges, repeated emails, corrupted counters. Clients are then afraid to retry, so transient failures become user-visible errors instead. Building reliable systems on top of non-idempotent operations is nearly impossible, because every layer must guarantee exactly-once delivery, which networks cannot. The cost surfaces as financial errors and data-integrity incidents that are hard to trace.
Warning Signs
- Retrying a request creates duplicate records or repeated effects.
- Mutating actions use POST with no deduplication mechanism.
- Clients disable retries to avoid duplicates, hurting reliability.
- Incident reports mention double charges or duplicate notifications.
Better Alternatives
Make operations idempotent. Use naturally idempotent HTTP methods where they fit: PUT and DELETE applied repeatedly leave the same state, and GET/HEAD are safe. For non-idempotent creates, support an idempotency key — a client-supplied unique token the server records, so a repeated request with the same key returns the original result instead of acting again. Use deduplication on a business key, or design for exactly-once-effect via stored request fingerprints.
How to Refactor Out of It
Inventory mutating endpoints and classify each as idempotent or not. For unsafe creates and charges, add idempotency-key support: persist key plus result, and on repeat return the stored outcome. Convert update operations to idempotent PUT semantics where appropriate. Add a unique constraint on business keys as a backstop against duplicates. Document the retry contract so clients can retry safely. Once retries are safe, the whole system becomes more resilient — you can retry aggressively without fear.