Error reference

Every error from the decode endpoint uses one uniform JSON envelope. This page documents the envelope shape and lists every error code, its HTTP status, whether it is retryable, and what triggers it.

The error envelope

A response is an error if and only if it contains a top-level error key. The error object always carries the same fields:

  • code — a stable, machine-readable identifier (the anchors on this page). Treat unknown codes by http_status and retryable.
  • http_status — the HTTP status, mirrored in the response line.
  • message — a human-readable explanation. Do not parse it.
  • details — a code-specific object (may be empty ); e.g. the offending parameter or a request_id.
  • retryable — whether retrying the same request can succeed.
  • retry_after_seconds — how long to wait before retrying, or null. When non-null it is mirrored in the Retry-After header.
  • docs — the absolute URL of the matching anchor on this page (https://txdecode.com/docs/errors#<code>).

Alongside error, every response also carries the decoder block (version and schema), and error responses are always sent with Cache-Control: no-store.

Error envelope — 400 invalid-tx-hash
{
  "error": {
    "code": "invalid-tx-hash",
    "http_status": 400,
    "message": "txHash must match ^0x[0-9a-fA-F]{64}$ (0x followed by 64 hex characters); received \"0x123abc\" (8 characters)",
    "details": { "received": "0x123abc", "expected_pattern": "^0x[0-9a-fA-F]{64}$" },
    "retryable": false,
    "retry_after_seconds": null,
    "docs": "https://txdecode.com/docs/errors#invalid-tx-hash"
  },
  "decoder": { "version": "1.0.0", "schema": "v1" }
}

No-settle guarantee. Non-200 responses are never settled — errors never cost $0.005. The x402 payment is only settled on a 200: any 4xx or 5xx response is returned before settlement, so a failed call costs nothing.

Two responses that are not this envelope

The 402 Payment Required paywall does not use this envelope. It returns the PaymentRequired structure of the x402 protocol (the accepted payment requirements: price, network, asset, payTo), which an x402 client reads to construct payment. A 402 is the normal first step of a paid call, not a failure.

The 429 rate-limited response, by contrast, is a pre-payment rejection and does use the envelope below — the rate limit is enforced before any payment, so it is never charged.

Error codes

One block per code. Each anchor (#<code>) is the target of the envelope's docs field.

invalid-tx-hash

HTTP status
400
Retryable
no
Retry after

When: Path param does not match `^0x[0-9a-fA-F]{64}$`.

Fix the hash before retrying — the path parameter is malformed, so a retry with the same value always fails.

invalid-parameter

HTTP status
400
Retryable
no
Retry after

When: Invalid query param (e.g. `verbose` ≠ true/false). Unknown params are ignored (forward-compat).

Fix the query parameter before retrying. Unknown parameters are ignored for forward compatibility, so only recognised parameters with invalid values trigger this.

tx-not-found

HTTP status
404
Retryable
no
Retry after

When: Well-formed hash unknown to the RPC fallback chain. May be another chain or a just-broadcast tx — see `details.note`.

Not retryable by default. The hash may belong to another chain, or it may have been broadcast seconds ago and not yet propagated to the RPC providers — see details.note before deciding to retry.

tx-pending

HTTP status
422
Retryable
yes
Retry after
3s

When: Transaction seen in mempool but no receipt yet: nothing to decode. Best-effort.

Retry after retry_after_seconds. The transaction is in the mempool but has no receipt yet, so there is nothing to decode. Mempool visibility on free RPCs is best-effort.

rate-limited

HTTP status
429
Retryable
yes
Retry after
Retry-After header

When: Pre-payment rate limit (30 requests per minute per IP per endpoint).

Retry after the Retry-After header. This limit is applied before payment, so a rate-limited request is never charged.

upstream-unavailable

HTTP status
503
Retryable
yes
Retry after
30s

When: All RPCs in the fallback chain are down, or the circuit breaker is open.

Retry after retry_after_seconds. Every RPC in the fallback chain is failing, or the circuit breaker is open; the request never reached a decode.

internal-error

HTTP status
500
Retryable
yes
Retry after

When: A bug on our side; `details.request_id` helps support.

Retryable, but report details.request_id to support if it persists — this is a fault on our side.