Skip to content

Retries and reorgs

Design RPC workflows for transient failures, best-effort consistency, and chain reorgs.

Recover from temporary failures without duplicating work, and keep stored data correct when the chain reorganizes. Match each retry to the kind of request, and store enough block identity to undo data from replaced blocks.

Prerequisites

  • A retry budget for your request path.
  • Logging for method, network, block reference, HTTP status, and JSON-RPC error code.
  • A durable cursor for long-running log or WebSocket workflows.

Retry guidance

Request typeRetry guidance
Current-state readsRetry 429, 502, 503, and 504 with backoff and jitter.
Historical readsRetry smaller ranges when a request times out or returns too much data.
eth_call simulationsRetry transport failures; treat EVM reverts as application results.
eth_sendRawTransactionRetry the same signed transaction; do not mutate and resubmit blindly.
Batch requestsRetry failed items individually.
WebSocket subscriptionsReconnect, resubscribe, and backfill missed blocks.

For every retry:

  • Use exponential backoff with jitter, and cap the total retry time.
  • Log the method, network, block reference or range, HTTP status, and JSON-RPC error code.
  • Pass the same explicit block number or hash when the retry must observe the same state as the first attempt. A retried latest read can land on a newer block.

See API integration for the meaning of each status and error code.

Handle reorgs

Recent blocks can be replaced by a chain reorganization. Logs you already processed from those blocks no longer describe the chain, and the replacement blocks can contain different logs.

A reorg replaces blocks N+1 and N+2. A logs subscription sends the replaced logs again with removed: true, then the logs from the new blocks. Keying logs by block hash keeps both versions apart; finalized blocks are not reorganized.
  1. Key stored logs by (blockHash, transactionHash, logIndex). The block hash keeps logs from a replaced block distinct from logs in its replacement.
  2. Over a WebSocket logs subscription, treat each log with removed: true as a reversal and delete or undo the matching stored log.
  3. When you poll with eth_getLogs, keep the block hashes of recent blocks you processed. Compare them with eth_getBlockByNumber on each poll, and replay from the last block whose hash still matches.
  4. For settlement, accounting, or other irreversible steps, act only on data at or behind the finalized block. Use safe when you can accept a small reorg risk for lower latency.

Next steps