Skip to main content
Partly proven

The failure class is proven below — a deliberately buggy handler and a fixed one were run against the same inputs, and they diverged. A fix on your own code has not been proven on this receipt. That is a separate claim, and only prove_fix establishes it — it reproduces the bug on your repository, applies your diff, and re-runs. Call it before you apply the fix, because it needs the still-broken tree.

sandbox · 2eb5d851fd15
11 other runs
Scoped to run run_3aeb1945-ed76-4d44-aaaf-fcf75eb83951.View all 12 runs →
Restored from a saved snapshot — payloads and results are exactly as captured.
2EB5D851FD15 · reference testBug reproduced

Duplicate webhook created a second charge

The same event was delivered twice.

Before the fix
2 deliveries → 2 charges
second delivery created another charge
After the fix
2 deliveries → 1 charge
second delivery recognized as duplicate
3 related checks passed0 unexpected failures2 webhook deliveries tested1 expected error responsetook 2437ms
FetchSandbox reference handlers. Behavioral simulation of a duplicate-webhook handler bug. Stripe delivers at-least-once, so payment_intent.succeeded can arrive 2-3x with the SAME event.id. Both handlers are FetchSandbox reference implementations, NOT your code: the buggy one processes every delivery (double charge), the fixed one dedupes on the stable event id. Apply the brain's fix_pattern (atomic dedup on event.id) to your handler to inherit this behavior.

what changed

The same request, before your fix vs. after — this is what the bug did, and what it does once fixed.

Before the fix
2 deliveries → 2 charges
  1. First deliverycharge 0 → 1
  2. Duplicate deliverycharge 1 → 2
  3. Finaldouble charge detected
After the fix
2 deliveries → 1 charge
  1. First deliverycharge 0 → 1
  2. Duplicate deliverystays 1
  3. Finalexactly 1 charge

request timeline

Before the fix · reference handler
After the fix · reference handler

run timeline

Every request and webhook the run made, in order.

  1. 05:55:37.386POST /v1/customers20016ms
  2. 05:55:37.419POST /v1/payment_intents20022ms
  3. 05:55:37.443POST /v1/payment_intents/pi_7R1M16ID52RJGJ83VC3N9DFQ/confirm20014ms
  4. 05:55:37.470POST /v1/payment_intents/pi_7R1M16ID52RJGJ83VC3N9DFQ/capture20016ms
  5. 05:55:37.495GET /v1/payment_intents/pi_7R1M16ID52RJGJ83VC3N9DFQ20014ms
ok failed webhook

full request history (5)

timetypepath / eventstatusdur

run metadata

sandbox id: 2d64d21288spec: 2eb5d851fd15status: runningscenario: defaultrun id: run_3aeb1945-ed76-4d44-aaaf-fcf75eb83951requests: 5
Generated by FetchSandbox — anyone with this link can read the proof.