JSON-RPC reserves the codes from -32000 to -32099 for server-defined errors, and Solana’s node defines twenty-one of them, -32001 through -32021. Most client libraries pass them through as a number and a string, parse two of them structurally, and leave you to search the number. Here is the whole list from the node’s source: what each code means, the message and data the node attaches, and the client action it calls for.
The useful discovery is that several of these errors are not failures. They are the node telling you something precise — its own lag, its retention floor, the block height a reward period ends — that no successful response would have told you.
Transactions
- -32002 — SendTransactionPreflightFailure. The simulation before send failed. The
datafield carries the entire simulation result: the error, the logs, units consumed, return data. This is the one code every client should parse, because the logs inside it are the diagnosis. Action: read the data; do not resend unchanged. - -32003 — TransactionSignatureVerificationFailure. A signature does not verify against the message. Action: a client bug; check the signing order and that the message was not modified after signing.
- -32006 — TransactionPrecompileVerificationFailure. An ed25519, secp256k1 or secp256r1 precompile instruction failed verification; the message names the precompile error. Action: for secp256r1 the usual cause is a high-S signature; normalise and retry.
- -32013 — TransactionSignatureLenMismatch. The number of signatures does not match the number the message requires. Action: client bug.
- -32015 — UnsupportedTransactionVersion. You asked for a versioned transaction without declaring support. The message contains the fix verbatim: retry with
maxSupportedTransactionVersionset to the version it names. Action: do exactly that.
Node state
- -32005 — NodeUnhealthy. The node is behind the cluster. If it knows by how much, the message reads “Node is behind by N slots” and
datacarriesnumSlotsBehind; otherwise “Node is unhealthy”. This is the only place a node volunteers its own lag. Action: fail over, and log the number — it is a free health metric for your provider. - -32008 — NoSnapshot. The node has no snapshot to serve. Action: another node.
- -32016 — MinContextSlotNotReached. You asked for a response at or after a slot (
minContextSlot) that this node has not reached;datacarries the node’s actualcontextSlot. Action: retry after a short wait, or route to a node that is ahead. The attached slot tells you how far behind this one is, which makes the code a free staleness probe. - -32021 — NoSlotHistory. The SlotHistory sysvar is unavailable, so a request that depends on it (block production, skipped-slot checks) cannot be answered. Action: another node.
History and archives
- -32001 — BlockCleanedUp. The slot you asked for is older than the node’s ledger retains. The message states “First available block: N” — the node’s retention floor. Action: route older queries to an archive endpoint, and record N; it is the boundary between hot and cold history on that provider.
- -32004 — BlockNotAvailable. The slot is within retention but the block is not present on this node — typically a slot it has not received or confirmed yet. Action: retry, or try another node.
- -32007 — SlotSkipped. The slot produced no block, or is missing because the node jumped to a recent snapshot. Action: not an error for your query; move to the next slot.
- -32009 — LongTermStorageSlotSkipped. The archive (Bigtable) has no block for the slot. Action: as above.
- -32011 — TransactionHistoryNotAvailable. The node does not serve transaction history at all (history is disabled on it). Action: a different provider.
- -32014 — BlockStatusNotAvailableYet. The block exists but its status (confirmed/finalized) is not yet known on this node. Action: retry.
- -32019 — LongTermStorageUnreachable. The archive backend could not be reached. Action: retry later; the hot path still works.
- -32020 — FilterTransactionNotFound. A
beforeoruntilsignature passed to a history query could not be found. Action: the pivot is wrong or not yet archived; drop it or wait.
Indexes, scans and epochs
- -32012 — ScanError. An accounts scan behind
getProgramAccountsor a similar query failed or was aborted on the node; the message carries the scan error. Action: narrow the filters, or retry on a node with the index you need. - -32010 — KeyExcludedFromSecondaryIndex. You asked
getProgramAccountswith a filter the node could have served from its token index, but the key you filtered on is excluded from that index on this node. Action: the query will not be fast here; narrow it or use a provider with a full index. - -32017 — EpochRewardsPeriodActive. You asked for an inflation reward while the epoch’s rewards are still being distributed;
datacarriesrewards_complete_block_height. Action: wait until the chain passes that block height, then retry. The number is the end of the distribution window for everyone. - -32018 — SlotNotEpochBoundary. A query that must be made at an epoch boundary was made at another slot. Action: use the epoch’s first slot.
What the reference client does with them
The stock Rust client parses exactly two of these into typed errors: -32002 and -32005. Everything else arrives as a code and a message string. The structured data the node attaches to -32016 (the actual context slot), -32017 (the completion height) and -32001 (the first available block) is sent and then discarded by the client, unless you read the raw response yourself.
If you build on top of an RPC — a bot, an indexer, a wallet backend — those three payloads are worth catching. They turn three failures into three measurements.
RPC Errors: Questions People Actually Ask
What does Solana RPC error -32005 mean?
The node is unhealthy or behind the cluster. If it knows its lag, the message reads “Node is behind by N slots” and the data carries the number. Fail over to another node and keep the number as a health signal.
What does error -32002 mean when sending a transaction?
The preflight simulation failed. The error’s data field contains the full simulation result, including the program logs, which is where the actual cause is.
How do I fix -32015 UnsupportedTransactionVersion?
Retry the request with maxSupportedTransactionVersion set to the version named in the message. The message states the fix verbatim.
What does -32016 MinContextSlotNotReached mean?
You asked for data at or after a slot this node has not reached. The data carries the node’s actual context slot, so you know how far behind it is; retry shortly or route to a node that is ahead.
The ones worth handling specially
-32002: read the simulation in data; it is the diagnosis.
-32005 and -32016: read the slot numbers; they are the node’s lag, measured by the node.
-32001: read the first available block; it is the provider’s retention boundary.
-32015: do what the message says.
-32017: wait for the block height it gives you.
The rest are “try another node” or “you have a client bug”, and the message says which.
The worst failures produce no code at all — the seven places a transaction disappears. -32015 is the code transaction v1 made common, and -32017’s block height is explained in when staking rewards arrive.
Constants read from the Agave validator source at commit beee69b958: rpc-client-api/src/custom_error.rs and rpc-client/src/http_sender.rs. Codes are added with releases — check the list against the version you run.