Reference note
UCP errors, retries, and idempotency in production
Separate UCP transport errors from business results, handle 409, 429, and 503, then retry without duplicating a transaction.
Published . Part of the UCP implementation guide.
A reliable UCP integration separates three cases: transport failed, negotiation produced an incompatible result, or a business resource needs correction. Applying the same retry policy to all three creates loops or duplicate transactions.
Key takeaways
- HTTP remains the primary signal for REST and MCP over HTTP.
- Capability incompatibility may return HTTP 200.
- Every retry of a state-changing operation must reuse its idempotency key.
Transport error or negotiation result?
Discovery failures mean a profile is missing, unreachable, or invalid. They use transport status codes: 400 for an invalid URL, 424 for an unreachable dependency, and 422 for a malformed profile or unsupported version.
An empty capability intersection is different. Processing completed, but no compatible
capability exists. In REST, capabilities_incompatible can therefore appear in an HTTP
200 response with ucp.status: "error". Checking only response.ok is insufficient.
Discovery codes are also listed in the UCP manifest guide.
Which statuses should trigger a retry?
| Status | Meaning | Response |
|---|---|---|
| 401 | authentication missing or invalid | refresh or request identity |
| 403 | insufficient permission | do not retry without changed scopes |
| 409 | same key, different payload | fix client state |
| 429 | rate limit | honor Retry-After |
| 500 | unexpected error | bounded retry based on operation |
| 503 | temporary unavailability | honor Retry-After |
For MCP over HTTP, the HTTP status is primary and the JSON-RPC code adds detail. The
specification recommends Retry-After in REST and error.data.retry_after in MCP for
429 and 503 responses.
How can a retry avoid duplicate effects?
An idempotency key identifies one logical attempt. It stays unchanged after a timeout, lost response, or 503. The server then returns the stored response without executing the operation again.
The key must be unique per client and operation type, with at least 128 bits of entropy. The server stores it for a minimum of 24 hours. If idempotency storage fails, UCP requires a closed failure with 503 because proceeding could create a duplicate effect.
The same key with a different body produces 409. The client must not bypass that conflict by immediately generating a new key. It should first determine which payload matches the real intent.
Recommended retry policy
- Classify the operation as read-only or state-changing.
- For a write, create the key before the first call and log it with a payload hash.
- After 429 or 503, wait as instructed and retry with the same key.
- After a timeout, read the resource before retrying when possible.
- Stop automation on 409 and compare payloads.
- Bound attempts and provide a human handoff.
Business messages need different handling
In Checkout, recoverable means correct inputs and call Update Checkout.
requires_buyer_input and requires_buyer_review require continue_url handoff.
unrecoverable requires a new resource or another path.
These severities are not network retry instructions. Exponential backoff cannot resolve a missing address or mandatory consent. Their role in the state machine is detailed in the UCP Checkout lifecycle.
Minimum observability
- HTTP status and UCP or JSON-RPC code;
- request identifier and a hash of the idempotency key;
- attempt number and applied delay;
- business state before and after the call;
- final decision: success, abandonment, or handoff.
Logs must not contain credentials, payment instruments, or full personal data.
Sources
- UCP, Overview and Error Handling, release 2026-08-25
- UCP, Message Signatures and replay protection
- UCP, Checkout error handling
Back to the UCP implementation guide · All notes · Lire en français