The payment settled. You can see it on chain. But the result never came back: the tool never executed, or it executed and the response got lost in a timeout, a proxy, or a crash after settlement.
The third most expensive x402 mistake is retrying that payment. It feels like the only option, and it is exactly the move that turns one lost result into two payments.
Two traps people walk into:
The double-payment trap. The retry signs a fresh EIP-3009 authorization for the same intent. If the first one settled (and a timeout or an opaque error told you nothing about whether it did), you have now paid twice. The protocol is blunt about the ambiguity: a duplicate submission of the same authorization can surface as a contract-level
AuthorizationUsedrevert, which looks identical to a genuine failure, so you cannot distinguish "already settled, stop" from "actually failed, try again" (x402-foundation/x402#452). Timeouts are worse: they describe what the wire did, not what the facilitator did, and the guidance from the tracker is direct that without a disciplined retry rule, "clients may retry in unsafe ways, potentially leading to duplicate payments" (x402-foundation/x402#831).The double-execution trap. Paying again usually means executing again. If the first execution ran and only the response was lost, the retry re-runs a job you already paid for and already consumed: a paid API call that mutates state, a purchase, a write. This is the double-jeopardy state: one retry, two failure modes, and each fresh signature is a fresh authorization to move funds.
Underneath both is a protocol-level gap. x402 moves your money to the seller reliably and then goes quiet about whether you got anything back. As the most-discussed issue in the x402 tracker puts it: "x402 solves how agents pay... None of these layers prove delivery." Escrow, reputation, and orchestration all need to answer "did the agent actually deliver what was paid for," and right now each either skips the check or trusts self-reporting (x402-foundation/x402#1195). On-chain settlement proves payment. It does not prove execution, and it certainly does not prove the result reached you. Treating a confirmed transaction as proof of delivery is how paid-no-result becomes undetectable, and article #1's signing-twice mistake wearing a new hat.
The safe sequence:
- Separate the three planes. Ask three distinct questions: did payment settle (check the chain for one confirmed transfer to the right recipient for the right amount)? Did execution happen (check the server's records, or ask the operator)? Did delivery happen (do you hold the result)? Most "paid but nothing happened" incidents are a delivery failure, not an execution failure, and re-execution is the wrong fix for a delivery failure.
-
Keep the settlement receipt. The spec's
PAYMENT-RESPONSEcarries the transaction hash. It is your proof of payment and your reconciliation handle. Contact the resource operator with it and ask whether execution occurred before you touch a retry. - Only re-execute when execution is proven not to have happened, or when the operation is provably idempotent. Evidence first, signature second. Never sign before you have checked what the first signature did.
- For agents: never auto-retry a paid-no-result. Park the operation for human review or evidence-gated recovery. An agent that retries paid operations on its own is a double-spend machine.
This is the failure class callx402 recover was built for. Hand it the recorded operation and it gives a read-only verdict on whether a retry is safe:
callx402 evidence op_abc123 # what happened, per plane
callx402 recover op_abc123 # safe-retry verdict: retry, wait, or ask
What it deliberately refuses to do: charge, execute, retry, or repay anything. A recovery tool that can re-sign is a recovery tool that can double-pay you, so recover is read-only by design. Two honest limits: the verdict is only as good as the evidence you hand it, and it cannot conjure delivery proof the protocol never produced. The three-plane check above is the narrowing tool for that; recover tells you which plane is still open.
Full writeups with sources in the callx402 troubleshooting docs: paid-but-no-result and when retry is safe. When x402 breaks, callx402.
Top comments (0)