agent generated a new idempotency key per retry: created 3 duplicate invoices
Makes retries reuse the same idempotency key so a flaky invoice create can't triple-bill. Use when duplicate invoices appeared after retries or an agent mints a fresh key per attempt. Not for distinct invoices sharing one key.
agent generated a new idempotency key per retry: created 3 duplicate invoices
TL;DR
Generate the idempotency key once per logical invoice and reuse it across every retry of that invoice; only mint a new key for a genuinely new invoice. If duplicates already exist, void the extras and keep the first. A retry must be byte-identical in key and payload, or the provider treats it as new work.
agent generated a new idempotency key per retry: created 3 duplicate invoicesFix it
- Create the key before the first attempt. Derive it deterministically from the invoice content (customer + lines + period) so retries naturally reproduce it. Success check: three simulated attempts with one forced timeout yield exactly one invoice.
- Pass the same payload with the same key. Don't tweak amounts or lines between retries; any change needs a new key and is a new invoice. Success check: retry logs show identical key and payload hash on every attempt.
- Bound the retries. Cap at 3-5 attempts with backoff, then escalate to a human instead of looping forever. Success check: a permanently failing endpoint stops after the cap with an alert.
- Clean up duplicates. List invoices for the customer/period, keep the earliest correct one, void the rest, and tell the customer. Success check: one active invoice remains and the voids are documented.
When this applies
- Duplicate invoices, charges, or subscriptions appeared after a retry loop ran.
- The agent generates a UUID per attempt instead of per operation.
When it doesn't
- Two distinct invoices collapsed into one; that is key reuse, the opposite bug.
- The duplicates came from two separate user actions (double-clicked submit); fix with client-side dedupe too.
Compatibility
- Pattern: agent retry loops on Stripe, Adyen, Chargebee, or any idempotent create endpoint.
- Deterministic key derivation works on any provider that accepts client-supplied keys.
Variant: agent retried a subscription create and billed 3x
Same fix: one key per intended subscription, reused across retries, duplicates canceled down to one.
Variant: timeout retries on payment intents
The create timed out but landed. Same fix: the retry with the same key replays the original intent instead of creating another.
Why it happens
Fresh UUID-per-attempt feels safe ("unique keys can't collide"), but it defeats the entire purpose of idempotency: the provider sees three different keys and faithfully creates three invoices. Uniqueness per attempt is the bug, not the fix.
Edge cases
- Payload drift: if a retry changes the payload, some providers 409 on key reuse; treat that as a signal you changed something, not as a bug.
- Key TTL: providers expire keys after ~24h; a retry days later is a new operation, which is usually what you want anyway.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_lNa7K-uxy1vywhUTOjVCjw