Skip to content

Error codes

This page lists the internal error codes Smart Router assigns to upstream failures, so you can look up a code from the router's logs or metrics and see whether it is retried.

Smart Router classifies every upstream failure into an internal error code. The router uses it for logging, metrics, and retry decisions. Each code has a name, a layer, and a retryable flag. The failover state machine reads this flag to decide whether to rotate to another node.

These codes are internal - clients never see them

Smart Router is a transparent hop. Your client always receives the original error from the upstream node, unchanged: the same JSON-RPC / HTTP / gRPC error you would get from the node directly. Lava error codes appear only in the router's logs and in the smartrouter_errors_total metric. Use this page to read those logs and metrics, not to handle codes on the wire.

The registry lives in protocol/common/error_registry.go.

The four layers at a glance

Layer Range Category Means Typical retryable?
PROTOCOL_* 1000s Internal The router's own internals: connection, session, consistency. Mostly yes
NODE_* 2000s External The node responded with an error (5xx, rate-limit, syncing, method-not-found). Mixed
CHAIN_* 3000s External The chain's execution/state layer (revert, nonce, block-not-found). Mixed
USER_* 4000s External The client sent a bad request (malformed JSON, invalid params). No

General rule: PROTOCOL_* / NODE_* 5xx errors are infrastructure noise that failover absorbs. A spike in CHAIN_* or USER_* usually means a client or contract problem, not a problem with your deployment.

Where you'll see these

In logs (structured fields on every classified failure):

{"level":"warn","error_name":"NODE_RATE_LIMITED","error_category":"external",
 "retryable":true,"chain_id":"ETH1","chain_error_code":429,
 "chain_error_message":"429 Too Many Requests","provider":"eth-publicnode"}

In metrics (smartrouter_errors_total, labelled by name/category/retryability/chain):

# Which errors are firing, by name?
sum by (error_name) (rate(smartrouter_errors_total[5m]))

# Terminal (non-retryable) errors only - these reach the client
sum by (error_name) (rate(smartrouter_errors_total{retryable="false"}[5m]))

Debugging with error codes

You see… Likely cause Next step
NODE_RATE_LIMITED climbing A node is throttling you Add upstreams, or check your node plan; failover already spreads load.
PROTOCOL_NO_PROVIDERS No node was left in the pool for a relay Every node was excluded. Check health and the circuit breaker.
CHAIN_STATE_PRUNED on historical queries The request reached a non-archive node Mark archive upstreams with the archive addon; see config.
NODE_METHOD_NOT_FOUND The node does not expose that method Terminal and cached. Confirm that the chain spec exposes it.
USER_* spike Clients sending bad requests Not an infrastructure issue. Inspect the client that sends them.
CHAIN_EXECUTION_REVERTED Contract reverted Expected for failing eth_call calls and simulations. Terminal, not retried.

How classification works

The router classifies errors with a two-level lookup that takes the chain family into account:

  1. Tier 2 - chain-specific matchers run first. They exist only where a chain's error has different retryability from the generic pattern (e.g. Solana -32009 vs -32007, Bitcoin warmup, Starknet class errors).
  2. Tier 1 - generic semantic matchers are the fallback. They are split by transport (jsonrpc / rest / grpc), so an EVM chain never evaluates gRPC matchers, and the reverse.

Connection-level failures (timeouts, refused, reset, context cancellation) are detected before either tier and always take precedence. Anything unmatched becomes UNKNOWN_ERROR (code 0, retryable).

Retry, CU, and caching

retryable is the main signal. A retryable: No classification stops retries on every terminal error, not only on unsupported methods. Two sub-categories have extra behaviour:

  • Unsupported method (NODE_METHOD_NOT_FOUND, NODE_UNIMPLEMENTED, NODE_ENDPOINT_NOT_FOUND, NODE_METHOD_NOT_ALLOWED) → zero retries, zero CU, response is cached, no node scoring. The node is not called again for it.
  • Rate limit (NODE_RATE_LIMITED) → back off without marking the endpoint unhealthy (it is busy, not broken).
  • User-input errors (USER_*) are non-retryable but charge normal CU. The response is not cached, because the next request from the same client may be valid, so the node still does real work.

Layer A - Protocol errors (PROTOCOL_*, 1000–1999)

Category: Internal. The Lava protocol itself raises these errors, not nodes or chains.

Code Name Description Retryable
1001 PROTOCOL_CONNECTION_TIMEOUT Network operation timed out connecting to node Yes
1002 PROTOCOL_CONNECTION_REFUSED Node connection refused Yes
1003 PROTOCOL_DNS_FAILURE DNS resolution failed Yes
1004 PROTOCOL_TLS_MISMATCH HTTP/HTTPS protocol mismatch No
1005 PROTOCOL_CONNECTION_RESET Connection reset by peer Yes
1006 PROTOCOL_CONNECTION_CLOSED Connection closed (EOF) Yes
1007 PROTOCOL_CONTEXT_DEADLINE Context deadline expired before the relay completed Yes
1008 PROTOCOL_CONTEXT_CANCELED Request context canceled (client disconnect or relay race resolved) No
1009 PROTOCOL_NETWORK_UNREACHABLE Network or host unreachable (no route) Yes
1010 PROTOCOL_NO_PROVIDERS No nodes/pairings available No
1011 PROTOCOL_ALL_ENDPOINTS_DISABLED All node endpoints disabled No
1012 PROTOCOL_PROVIDER_UNAVAILABLE Node service unavailable (gRPC UNAVAILABLE) Yes
1013 PROTOCOL_PROVIDER_ABORTED Node aborted (gRPC ABORTED) Yes
1014 PROTOCOL_PROVIDER_DATA_LOSS Node data loss (gRPC DATA_LOSS) Yes
1015 PROTOCOL_INSUFFICIENT_PROVIDERS Insufficient providers available for addon or cross-validation No
1020 PROTOCOL_RATE_LIMITED Lava-side rate limit exceeded No
1021 PROTOCOL_MAX_CU_EXCEEDED Maximum compute units exceeded for session No
1022 PROTOCOL_BATCH_SIZE_EXCEEDED Batch request size exceeded limit No
1023 PROTOCOL_CU_MISMATCH CU accounting inconsistency or security violation No
1030 PROTOCOL_SESSION_NOT_FOUND Session does not exist No
1031 PROTOCOL_EPOCH_MISMATCH Epoch mismatch or too old No
1032 PROTOCOL_CONSUMER_BLOCKED Consumer is blocklisted No
1033 PROTOCOL_CONSUMER_NOT_REGISTERED Consumer not registered No
1034 PROTOCOL_RELAY_NUMBER_MISMATCH Relay number mismatch No
1035 PROTOCOL_SESSION_OUT_OF_SYNC Session out of sync No
1036 PROTOCOL_INVALID_RELAY_REQUEST Relay request validation failed (wrong provider/specID/chainID/seen block/content hash) No
1037 PROTOCOL_REQUEST_BLOCK_MISMATCH Block height mismatch between consumer request and provider state Yes
1038 PROTOCOL_SESSION_ACCOUNTING_FAILED Session accounting (OnSessionDone/OnSessionFailure) failed No
1039 PROTOCOL_SUBSCRIPTION_CLEANUP_FAILED Subscription consumer removal (RemoveConsumer) failed No
1040 PROTOCOL_FINALIZATION_ERROR Node finalization data incorrect Yes
1041 PROTOCOL_CONSISTENCY_ERROR Response consistency validation failed Yes
1042 PROTOCOL_HASH_CONSENSUS_ERROR Conflicting response hashes detected Yes
1043 PROTOCOL_NO_RESPONSE_TIMEOUT Relay race timeout - no node returned within the deadline Yes
1044 PROTOCOL_RELAY_PROCESSING_FAILED Relay response processing failed on consumer side Yes
1050 PROTOCOL_SUBSCRIPTION_NOT_FOUND Subscription not found No
1051 PROTOCOL_SUBSCRIPTION_INIT_FAILED Failed to initialize subscription No
1052 PROTOCOL_WEBSOCKET_IDLE_TIMEOUT WebSocket idle timeout No
1053 PROTOCOL_SUBSCRIPTION_ALREADY_EXISTS Subscription already exists for this consumer/key No

Layer B - Node errors (NODE_*, 2000–2999)

Category: External. The blockchain node itself returns these errors (they are not execution or state errors). "Standard code" is the protocol-level code that the matcher looks for.

Code Name Description Retryable Standard code
2001 NODE_METHOD_NOT_FOUND Method does not exist on this node (unknown to the API surface) No JSON-RPC -32601
2002 NODE_METHOD_NOT_SUPPORTED Method exists but is disabled on this node; retryable on a different node Yes JSON-RPC -32004
2003 NODE_INTERNAL_ERROR Internal node error Yes JSON-RPC -32603
2004 NODE_SERVER_ERROR Generic server error Yes JSON-RPC -32000
2005 NODE_RATE_LIMITED Rate limited by node Yes HTTP 429
2006 NODE_SERVICE_UNAVAILABLE Node temporarily unavailable Yes HTTP 503
2007 NODE_SYNCING Node is syncing/catching up Yes message match
2008 NODE_UNIMPLEMENTED gRPC method unimplemented No gRPC 12
2009 NODE_ENDPOINT_NOT_FOUND REST endpoint not found No HTTP 404
2010 NODE_METHOD_NOT_ALLOWED REST method not allowed No HTTP 405
2011 NODE_LIMIT_EXCEEDED Request exceeds node limit (e.g. eth_getLogs range) No JSON-RPC -32005
2012 NODE_RESOURCE_NOT_FOUND Resource not found at node level Yes JSON-RPC -32001
2013 NODE_RESOURCE_UNAVAILABLE Resource exists but unavailable Yes JSON-RPC -32002
2014 NODE_GATEWAY_TIMEOUT Gateway timeout from node Yes HTTP 504
2015 NODE_BAD_GATEWAY Bad gateway from node Yes HTTP 502
2016 NODE_UNAUTHORIZED Upstream rejected router credentials (HTTP 401) No HTTP 401
2101 NODE_BITCOIN_WARMUP Node still warming up (Bitcoin -28) Yes -
2102 NODE_BITCOIN_INITIAL_DOWNLOAD Node in initial block download (Bitcoin -10) Yes -
2103 NODE_BITCOIN_NOT_CONNECTED Node has no peers (Bitcoin -9) Yes -
2150 NODE_SOLANA_UNHEALTHY Solana node behind/unhealthy (-32005) Yes -

Layer C - Blockchain errors (CHAIN_*, 3000–3999)

Category: External. These errors come from the blockchain execution and state layer: transaction failures, state queries, and similar. Tier-2 (chain-specific) codes exist only where retryability differs from the generic pattern.

Transaction errors (3000–3099)

Code Name Description Retryable Chains
3001 CHAIN_NONCE_TOO_LOW Nonce/sequence too low No EVM, Cosmos, Starknet, XRP, NEAR
3002 CHAIN_NONCE_TOO_HIGH Nonce too high No EVM, XRP
3003 CHAIN_INSUFFICIENT_FUNDS Insufficient funds for transfer/gas No Universal
3004 CHAIN_GAS_TOO_LOW Intrinsic gas too low No EVM
3005 CHAIN_GAS_LIMIT_EXCEEDED Exceeds block gas limit No EVM
3006 CHAIN_TX_UNDERPRICED Transaction gas price too low No EVM
3007 CHAIN_TX_ALREADY_KNOWN Transaction already in mempool No EVM, Starknet, XRP
3008 CHAIN_TX_REPLACEMENT_UNDERPRICED Replacement tx gas too low No EVM
3009 CHAIN_MEMPOOL_FULL Mempool/tx pool is full No EVM, Cosmos
3010 CHAIN_TX_TOO_LARGE Transaction exceeds size limit No EVM, Solana
3011 CHAIN_MAX_FEE_BELOW_BASE Max fee per gas below base fee No EVM (EIP-1559)
3012 CHAIN_INVALID_SEQUENCE Invalid sequence (Cosmos nonce equivalent) No Cosmos
3013 CHAIN_INSUFFICIENT_FEE Insufficient fee No Cosmos
3014 CHAIN_TX_REJECTED Transaction rejected by network rules No Universal
3015 CHAIN_DOUBLE_SPEND Double spend / UTXO already spent No Bitcoin/UTXO
3016 CHAIN_INVALID_SIGNATURE Invalid transaction signature No Universal

Execution errors (3100–3199)

Code Name Description Retryable Chains
3101 CHAIN_EXECUTION_REVERTED Smart contract execution reverted No EVM, Starknet, NEAR, TON
3102 CHAIN_OUT_OF_GAS Out of gas during execution No EVM, Cosmos, TON
3103 CHAIN_STACK_OVERFLOW Stack limit reached No EVM, TON
3104 CHAIN_INVALID_OPCODE Invalid opcode encountered No EVM, TON
3105 CHAIN_WRITE_PROTECTION Write in STATICCALL context No EVM
3106 CHAIN_CONTRACT_SIZE_EXCEEDED Contract bytecode exceeds 24KB EIP-170 limit No EVM
3107 CHAIN_ACCOUNT_NOT_FOUND Account/contract does not exist No Cosmos
3108 CHAIN_ZKEVM_OUT_OF_COUNTERS Polygon zkEVM prover exceeded circuit counter budget No EVM (Polygon zkEVM)

State / data errors (3200–3299)

Code Name Description Retryable Chains
3201 CHAIN_BLOCK_NOT_FOUND Block not found Yes Universal
3202 CHAIN_TX_NOT_FOUND Transaction not found Yes Universal
3203 CHAIN_RECEIPT_NOT_FOUND Transaction receipt not found Yes EVM (Cosmos-EVM variant)
3204 CHAIN_STATE_PRUNED State pruned/missing trie node Yes EVM
3205 CHAIN_DATA_NOT_AVAILABLE Historical data not available Yes Universal
3206 CHAIN_BLOCK_TOO_OLD Block results only for recent blocks Yes Cosmos
3207 CHAIN_LOG_RESPONSE_TOO_LARGE Log query returned too many results No EVM

Chain-specific Tier-2 ranges also exist for Solana (3300–3319), Starknet (3320–3339), Bitcoin/UTXO (3340–3359), and NEAR (3360–3379). See the registry source for the full list. Most are non-retryable. The retryable exceptions are the Solana CHAIN_SOLANA_LEDGER_JUMP, CHAIN_SOLANA_BLOCK_STATUS_UNAVAILABLE, and CHAIN_SOLANA_MIN_CONTEXT_SLOT_NOT_REACHED; the Starknet CHAIN_STARKNET_BLOCK_NOT_FOUND, CHAIN_STARKNET_TX_HASH_NOT_FOUND, and CHAIN_STARKNET_UNEXPECTED_ERROR; and the NEAR block/chunk garbage-collection codes (CHAIN_NEAR_UNKNOWN_BLOCK, CHAIN_NEAR_UNKNOWN_CHUNK, CHAIN_NEAR_NOT_SYNCED_YET).


Layer D - User errors (USER_*, 4000–4999)

Category: External. These are malformed or invalid client requests. They are classified by the nature of the error, whether Lava catches it before forwarding or the node returns it. All are non-retryable, and all charge normal CU (responses are not cached).

Code Name Description Retryable Standard code
4001 USER_PARSE_ERROR Invalid JSON in request No JSON-RPC -32700
4002 USER_INVALID_REQUEST Not a valid JSON-RPC/REST/gRPC object. Also returned by the router, before any node is called, for a JSON-RPC batch carrying an XRP Ledger submit or submit_multisigned (see XRP Ledger submit verdicts) No JSON-RPC -32600
4003 USER_INVALID_PARAMS Invalid method parameters No JSON-RPC -32602
4004 USER_INVALID_BLOCK_FORMAT Invalid block number format (e.g. non-hex) No message match
4005 USER_INVALID_ADDRESS Invalid address format No message match
4006 USER_REQUEST_TOO_LARGE Request body exceeds size limit No HTTP 413
4007 USER_INVALID_HEX Invalid hex encoding No message match

XRP Ledger submit verdicts

An XRP Ledger node reports the outcome of a transaction inside an ordinary HTTP 200 result, not in a JSON-RPC error object. So on a submit or submit_multisigned reply, the router reads result.engine_result (and result.error when the call itself failed) and classifies both:

Reply Treated as Example codes
tesSUCCESS, terQUEUED Success -
tec* (applied, fee claimed) Success: the transaction's final outcome, not a refusal -
tef*, tem*, tel*, other ter* Node error CHAIN_NONCE_TOO_LOW (tefPAST_SEQ), CHAIN_TX_ALREADY_KNOWN (tefALREADY), CHAIN_NONCE_TOO_HIGH (terPRE_SEQ), CHAIN_TX_REJECTED (the rest)
A catalogued API error beside "status":"error" Node error NODE_SYNCING (noNetwork, notSynced), NODE_SERVICE_UNAVAILABLE (amendmentBlocked), NODE_RATE_LIMITED (tooBusy, slowDown), NODE_INTERNAL_ERROR (internal*), USER_INVALID_PARAMS (invalidTransaction, notSupported, …)

This matters for writes. A transaction submission is broadcast to every upstream, and the caller gets the first success. If the router read a rejection as a success, it would end that broadcast early. A node that already had the transaction through peer gossip could answer tefPAST_SEQ before the node that applied it answered tesSUCCESS. The caller would then be told that a validated payment had failed.

These replies carry lava-identified-node-error: true (see Response headers). A ledger verdict is non-retryable and is not charged against the answering node's availability, because the node reported the truth. An API error about the node's own state, such as noNetwork, is charged against it.

Every other XRPL method keeps the envelope rule: an engine result in any other reply, such as the one simulate returns, is the answer the caller asked for. A batch that carries a submit is refused with USER_INVALID_REQUEST before any node is called. The reason is that a batch is classified by its envelopes alone, so a rejection inside one would again read as a success.


Chain families

Tier-2 classification is based on a chain's family. An unregistered chain id resolves to the Unknown sentinel. Tier-2 lookups then miss on purpose, and classification falls through to the transport-scoped Tier-1 matchers.

Family Example chain ids
EVM ETH1, SEP1, HOL1, ARBITRUM, POLYGON, BASE, OPTM, AVAX, BSC, BLAST, FTM250, SONIC, …
Solana SOLANA, SOLANAT, KOII, KOIIT
Bitcoin BTC, BTCT, LTC, LTCT, DOGE, DOGET, BCH, BCHT
CosmosSDK COSMOSHUB, LAVA, LAV1, AXELAR, EVMOS, OSMOSIS, JUN1, CELESTIA, …
Starknet STRK, STRKS
Aptos APT1
Sui SUIT
NEAR NEAR, NEART
XRP XRP, XRPT
Stellar XLM, XLMT
TON TON, TONT
Tron TRX, TRXT
Cardano CARDANO, CARDANOT
Unknown sentinel - Tier-2 misses, falls through to Tier-1