Skip to main content
By the end of this page you will know the shape of a Rail402 rejection, the guarantee it makes, how to branch on it in code, and the notable codes you are most likely to hit. This is the reference for @rail402.dev/errors, which the facilitator, the Bazaar, the MCP server, and the SDK all share.

The shape

Every rejection is a { code, reason, retryable } object.
The guarantee: every rejection across the facilitator, the Bazaar, and the MCP server carries a non-null reason. There is no null, empty, or missing reason anywhere. An agent can reason about a failure without parsing prose.

Handling errors

@rail402.dev/errors (also at @rail402.dev/sdk/errors) exports the registry and the helpers.
The SDK’s buyer functions surface the same shape as result.error, so you branch on code the same way whether you caught an X402Error or read a Result.
Look up any code’s registered reason and retryability without triggering it:

Retryable means retryable

retryable: true is reserved for genuinely transient conditions, such as rate limiting or a network submission failure. Everything else is false. Respect the flag. Retrying a non-retryable failure loops forever, and one code in particular means the money already moved, so a retry pays twice.
mcp_paid_but_resource_failed is not retryable. The payment settled and then the resource returned an error. The funds have already moved on chain. Do not retry. See Troubleshooting.

Notable codes

A small slice of the registry, covering the failures you meet first. Use ALL_ERROR_CODES and ERROR_REGISTRY to enumerate the full set at runtime.

Next steps

Troubleshooting

Symptom, cause, and fix for the common failures.

SDK reference

Where these codes surface in result.error.

FAQ

Answers to the questions behind many rejections.

Packages

Where the errors package fits.