Reliability
Which Corvus Solana RPC errors are retryable, how gRPC and aRPC streams recover, and why acceptance of a transaction is not confirmation.
Every gateway failure carries a code and a stable message prefix, and between them they tell you whether a second attempt could ever work, and what to change before you make it.
Retrying
| Code and prefix | HTTP | Retryable | What to change before the next attempt |
|---|---|---|---|
-32600 Invalid request body | 400 | No | Fix serialization. The identical body will fail forever. |
-32002 Unauthorized | 401 | No | Wrong egress IP, missing token, or wrong tokenized path. |
-32003 You have no access to this service | 403 | No | The resource does not include that product. Ask on Discord. |
-32001 RPS limit exceeded | 429 | Yes | Reduce weighted cost, not request count; batch items and getMultipleAccounts accounts are charged individually. |
-32005 Transaction rate limit exceeded | 429 | Yes | Pace to your TPS allowance, then resend the same signed bytes while the blockhash is valid. |
-32005 Scan request timed out waiting for concurrency slot | 429 | Yes | Lower scan concurrency first. Retrying at the same concurrency re-enters the same queue. |
-32000 Unable to process Batch Request | 502 | Yes | Split the batch and retry idempotent items individually. |
-32099 Server is not available at the moment | 503 | Yes | Retry idempotent reads with bounded backoff. |
Classify on status and code and prefix, never on the message alone; messages can pick up a trailing support sentence, and -32005 covers two conditions.
// Terminal at the gateway: a second identical request cannot succeed.
const terminal = new Set([-32600, -32002, -32003]);
function shouldRetry(httpStatus: number, code: number) {
if (terminal.has(code)) return false;
return httpStatus === 429 || httpStatus === 502 || httpStatus === 503;
}We reject rather than queue, so any pacing happens on your side.
Recover gRPC and aRPC streams
Liveness
aRPC v2 sends a server heartbeat every 10 seconds. That's your liveness signal.
Sequence gaps cannot happen
aRPC v2 sequence starts at 0 inside each per-stream handler and increments right before every message goes out. It's a contiguous per-stream counter over everything on that stream, so you can never observe a gap. A "sequence discontinuity" detector reports nothing, and hides real loss behind a green metric while it does. Keep sequence for ordering and logging.
sequence is connection-local, resets on reconnect, and isn't a replay cursor. Neither the legacy nor the v2 aRPC API has a resume request, so after a reconnect you send the whole subscription set again and reconcile what you missed through JSON-RPC.
Yellowstone gRPC is the exception: pass from_slot on the re-subscribe and the stream replays what the backend retains from that slot before going live. Replay on reconnect has the contract.
Filter updates
Registrations are acknowledged per filter with a FilterValidationResult; unregistrations aren't acknowledged, and an entry with an empty filter_id is skipped. Batch related filters into one registration message and match results by filter_id; aRPC limits & operations has the rest of the aRPC stream contract.
Two rejections behave unlike the rest
Opening and cancelling streams too rapidly is handled one layer down and never reaches you as a gRPC reason: the server closes the connection with an HTTP/2 GOAWAY carrying ENHANCE_YOUR_CALM. What you back off there is the churn, not just the connection.
A PERMISSION_DENIED carrying PPS limit requirement not met closes the connection, and the next connection meets exactly the same condition; see Gateway & streaming errors.
Confirm transactions by signature
Acceptance is not confirmation
A 200 response, a returned signature, a QUIC acknowledgement, a sent UDP datagram: they all mean the bytes were accepted for submission, not that the transaction landed. Confirm the signature through Solana RPC.
Falcon does have signature-keyed duplicate suppression, but it only applies after a submission has been delivered. So resending the same signed bytes while the blockhash is valid is still the right retry: it isn't wasted, and it isn't blocked.
Three Falcon rejections are properties of the transaction itself (size, tip amount, tip recipient) and need a rebuild and a re-sign rather than a retry. Falcon errors & retries and Tips have the exact rules.
Treat streaming data as pre-execution
aRPC and Shredstream hand you data before it executes. That's the point of them, and it's also the risk:
- Slot
COMPLETEis not confirmation and not finality. - Shredstream is fire-and-forget UDP: loss, reordering and duplication are all normal.
Network path
Regional failure is handled behind the endpoint: backends are health-checked, and a degraded region serves you from a healthy one until it recovers (regional failover). Solana RPC is served from five metros while Falcon, aRPC and Shredstream run in nine, so if you rent a second region for your own redundancy, it may not carry every product you use. See Regions.