Errors

HTTP, JSON-RPC, WebSocket and gRPC error codes, their causes and their fixes.

Errors come from two places. The constant-k gateway checks your key and your limits before a request reaches a node, and answers with an HTTP error status such as 401 or 403. The Solana node runs the method and answers with a JSON-RPC error object.

{
  "jsonrpc": "2.0",
  "error": { "code": -32602, "message": "Invalid param: WrongSize" },
  "id": 1
}

Some errors also carry a data field with details, such as simulation logs.

Gateway errors

The gateway answers with a JSON-RPC error body and "id": null, except the getTokenLargestAccounts concurrency 429, which echoes the request id. Placeholders in angle brackets are filled in with the method, the category or the limit that was hit.

HTTP statusCodeMessageCause and fix
401-32600Missing API keyNo key was sent. Add it to the URL or a header. See Authentication.
403-32600Invalid API keyThe key is wrong or was re-rolled. Copy it again from My Account.
403-32600<method> requires higher tierThe method is not on your plan, for example getLatestBlockhash on Free. Upgrade, or call a method your plan includes. See Plans & Limits.
403-32600<method> not supportedThe method is not served on any plan: getLargestAccounts, sendBundle and a few methods Solana has removed. Retrying will not help.
400-32600Batch requests are not supportedThe body is a JSON array. Send one call per request. Even a one-element array is rejected.
400-32600<method> requests a maximum of 100 items (<N> requested)getMultipleAccounts and getSignatureStatuses take at most 100 items. Split the list.
429-32005Global rate limit exceeded (<N>/sec, batch of <B>)You went over your plan's total requests per second.
429-32005Rate limit exceeded (<category>: <N>/sec)You went over the cap for that group of methods, such as heavy block and history calls.
429-32005Global <method> capacity reached (<N>/sec across all keys); retry shortlyThat method is at capacity for every key, not only yours. Retry shortly.
429-32005getProgramAccounts concurrency limit reached (per-key); retry shortlyYour API key already has as many getProgramAccounts and getProgramAccountsV2 calls in progress as its plan allows: 1 on Blade Runner, 3 on Nexus. Retry when one of them finishes.
429-32005Node is unhealthyToo many getTokenLargestAccounts requests were in progress at once, from your key or from all keys together, and this one could not start within 5 seconds. Retry after a short pause.
503-32005getTokenLargestAccounts is temporarily unavailable; retry shortlygetTokenLargestAccounts is temporarily unavailable, or cannot be answered at the requested commitment at that moment. Retry shortly.
503-32000a congestion message ending retry shortlyThe region is shedding load. The response carries a Retry-After header. Wait that many seconds, then retry.

A rate-limit 429 carries no wait time

Rate-limit responses (-32005) carry no Retry-After header and no X-RateLimit-* or RateLimit-* headers, so backoff is the client's own job. Budgets are counted in whole seconds and reset at the start of each new second, so a short wait is usually enough. See How rate limits work.

Long-term storage responses

On Blade Runner and Nexus tier plans, Cube Runner retrieves a block from long-term storage when no cache, ledger or other region holds it. A getBlock request returns the block when it is retrieved within 25 seconds. Otherwise the response is HTTP 429 with a Retry-After header and code -32019, and it echoes the request id.

HTTP statusCodeMessageCause and fix
429-32019Block <slot> is being retrieved from long-term storage; retry in <N> secondsThe block is queued and stays queued. Wait Retry-After seconds, then send the same request again. See Queued requests.
429-32019A message stating the reasonThe block was not queued, was dropped from the queue, or was not returned by long-term storage. data.reason names the cause: queue_full, key_full, key_monthly, dropped or failed. See Responses that are not queued.

Standard JSON-RPC errors

CodeMessageWhat it means
-32700Parse errorThe body is not valid JSON.
-32600Invalid requestThe body is not a valid JSON-RPC 2.0 request.
-32601Method not foundThe method name is wrong or does not exist. Method names are case sensitive.
-32602Invalid paramsA parameter is missing or has the wrong type or format, for example a malformed address.
-32603Internal errorThe node failed while it handled the call. Retry with backoff.

Solana node errors

These codes come from the node software, as do their messages.

CodeMeaningWhat to do
-32001Block not available. For getBlock on Free and Operator tier plans, no cache, ledger or other region holds the block. For other methods, the block is older than the region's ledger. The message gives the first available block.Ask for a slot at or above that block. On Blade Runner and Nexus tier plans, Cube Runner retrieves such a block from long-term storage instead.
-32002Transaction simulation (preflight) failed. data holds the error and the logs.Read data.logs, fix the transaction, then resend. See Transaction errors.
-32003Transaction signature verification failed.Sign after the message is final, with every required signer.
-32004Block not available for this slot.The block may not be ready yet. Retry shortly.
-32005Node is unhealthy or behind. data may show how many slots behind.Retry with backoff, or use another region.
-32006Precompile verification failed (for example an Ed25519 or secp256k1 instruction).Check the precompile instruction data.
-32007The slot was skipped: no block was produced.Normal on Solana. Move on to the next slot.
-32008No snapshot is available.Retry later.
-32009The slot was skipped, or is missing in long-term storage.Treat it as skipped.
-32010The key is excluded from the account secondary index, so this method is unavailable for it.Query this account another way, or contact support.
-32011Transaction history is not available from this node.Retry, or contact support if it persists.
-32012Scan error, for example when an account scan returns too much data.Add or tighten filters, and use dataSlice.
-32013Transaction signature length mismatch.The number of signatures does not match the message. Rebuild the transaction.
-32014Block status is not available yet for this slot.Retry shortly.
-32015Unsupported transaction version.Pass "maxSupportedTransactionVersion": 1. See Transaction version errors.
-32016Minimum context slot not reached. The node has not yet seen the minContextSlot you asked for.Retry shortly.
-32017Epoch rewards are still being paid out.Retry after the rewards period ends.
-32018The slot is not an epoch boundary, so rewards cannot be found.Check the epoch or slot you passed.
-32019For getBlock, the block is queued for retrieval from long-term storage, or was not retrieved. See Long-term storage responses.Wait Retry-After seconds when the response carries it, then send the same request again. Otherwise retry with backoff.
-32020The transaction you filtered for was not found.Check the signature.
-32021No slot history.Retry later.

Transaction version errors

getBlock, getTransaction and blockSubscribe take a maxSupportedTransactionVersion parameter that says which formats your client can decode. Two errors come from getting it wrong.

CodeCauseFix
-32015The parameter is missing, or its value is below the version of a transaction in the response. The number in the message is the version the node found, not the value to send.Send "maxSupportedTransactionVersion": 1.
-32602The value is the string "1" instead of the integer 1. The node rejects the whole config object, so the message does not name the field.Send the JSON number 1, with no quotes.

The ceiling is raised after the client can decode the format, not before. Transaction v1 has the full error bodies, the client minimums and the migration steps.

Transaction errors

When preflight is on, a failed simulation returns -32002 and the send is rejected. The data object holds the transaction error and the program logs:

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32002,
    "message": "Transaction simulation failed: Error processing Instruction 2: custom program error: 0x1",
    "data": {
      "err": { "InstructionError": [2, { "Custom": 1 }] },
      "logs": ["Program 11111111111111111111111111111111 invoke [1]", "…"]
    }
  },
  "id": 1
}
ErrorCause
BlockhashNotFoundThe blockhash is too old or unknown to this node. A fresh one is needed.
InsufficientFundsForFeeThe fee payer cannot pay the fee.
InstructionError with CustomA program returned its own error code. The program's IDL or source defines it.
AlreadyProcessedThis exact transaction already landed. A resend is redundant.

With skipPreflight: true, the send succeeds even if the transaction would fail. getSignatureStatuses gives the result: a landed but failed transaction has a non-null err.

In @solana/kit, the error carries its own context:

import {
  createSolanaRpc,
  isSolanaError,
  SOLANA_ERROR__JSON_RPC__SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE,
  SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR,
} from "@solana/kit";

const rpc = createSolanaRpc(
  `https://rpc-newyork.constant-k.com/?api-key=${process.env.CK_API_KEY}`,
);

// wireTx: a signed, base64-encoded transaction (see Sending Transactions)
try {
  await rpc.sendTransaction(wireTx, { encoding: "base64" }).send();
} catch (e) {
  if (isSolanaError(e, SOLANA_ERROR__JSON_RPC__SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE)) {
    // Simulation failed: the logs usually say why
    console.error(e.context.logs);
    console.error(e.cause); // the transaction error
  } else if (isSolanaError(e, SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR)) {
    // Rejected by the gateway, for example 401 or 403
    console.error("HTTP", e.context.statusCode);
  } else {
    throw e;
  }
}

WebSocket errors

A failed subscribe returns a JSON-RPC error frame with the codes above, for example -32602 for a bad address, and the connection stays open.

CodeCauseWhat to do
Close 1006, right after the connection opensThe key is missing or invalid, or your plan does not include WebSockets. The handshake succeeds first, so there is no close frame.Check the key and the plan.
Close 1013You opened connections too fast, or you are at your plan's connection limit.Read the close reason. Back off and reconnect.
-32005 frameYou are over a rate limit or at the subscription cap.Unsubscribe, or open another connection.
-32602 frame on blockSubscribeThe options object is missing "maxSupportedTransactionVersion": 1, or sent it as a string. The check runs at subscribe time.Send the integer 1.
-32600 frame with "id": null, every few secondsYour client is sending its own ping message. The stream is healthy.Ignore it. See WebSockets.
Error frame for a non-subscription methodOnly subscription methods and getHealth are allowed.Send the call over HTTPS.

gRPC errors

These apply to Kaldera, Turbo Kaldera and ShredPrism.

StatusWhenWhat to do
UNAUTHENTICATED (16)The x-token header is missing or wrong. The message is Missing or Invalid API Key.Check the key and the header name.
INVALID_ARGUMENT (3)The subscribe request is malformed or breaks a filter limit.Check the request against Filters and the plan limits.
OUT_OF_RANGE (11)In standard Yellowstone, fromSlot is older than the replay window.Resubscribe with a newer slot, or without fromSlot. See Replay.
UNAVAILABLE (14)The connection dropped or the server is restarting.Reconnect with exponential backoff.

Some clients report a failed login differently:

  • @triton-one/yellowstone-grpc (TypeScript): failed to open subscribe stream.
  • grpcurl and other grpc-go tools: unexpected HTTP status code received from server: 204 (No Content).
  • yellowstone-grpc-client (Rust): code: 'The request does not have valid authentication credentials', message: "Missing or Invalid API Key".

When to retry

Retryable with exponential backoffNot retryable until something changes
Network errors, HTTP 429 and 5xx, -32603, -32005, -32004, -32014, -32016, -32019, gRPC UNAVAILABLE400, 401, 403, -32600, -32601, -32602, -32002, -32003, -32013, -32015, gRPC UNAUTHENTICATED and INVALID_ARGUMENT

Backoff starts at about 250 ms, doubles each time, carries random jitter, and caps at a few seconds. A response with a Retry-After header sets the wait instead. WebSocket and gRPC streams use the same backoff, then resubscribe.

On this page