fix(rpc): retry a bare HTTP 500 and pre-check failures of traced mined blocks - #587
Merged
Merged
Conversation
mo4islona
force-pushed
the
fix/rpc-retry-bare-500-and-trace-precheck
branch
from
October 1, 2026 08:59
9d1610c to
0e70608
Compare
…d blocks A 500 whose body is not a JSON-RPC response comes from a proxy in front of the node, and the same call succeeds when repeated. A 500 with a JSON-RPC envelope stays fatal: Bitcoin Core and others answer ordinary errors that way. A proxy can also label its error page or an empty body as JSON, so an error body that does not parse is kept as text for the status check instead of failing as a parse error. A transaction in a block passed its pre-checks when it was mined, so a trace of that block failing them means the serving node has wrong state for it. These errors are retried for replay traces whatever code or proxy cause they come under, including one error for a whole batch of a single method, and counted as `wrong_state`, so a node that never recovers shows up in the metrics as the dump stalls. Closes #585 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
mo4islona
force-pushed
the
fix/rpc-retry-bare-500-and-trace-precheck
branch
from
October 1, 2026 09:27
e0a9b8d to
2b6e298
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two failures that go away when the same call is repeated were classified as permanent, so
evm-dumpexited and restarted instead of retrying. Closes #585.Changes
RpcClient.isConnectionError: an HTTP 500 is retried unless its body is a JSON-RPC response.jsonrpcorid) and an outcome (resultorerror). Bitcoin Core's JSON-RPC 1.0 errors, which haveidbut nojsonrpc, therefore stay fatal, and so does a JSON-RPC body sent as text or bytes.{"error": {"message": "Internal Server Error"}}, comes from a proxy in front of the node failing and is retried.RpcClientgets this,EvmRpcClientincluded.rpcMethodif every call in the batch has the same method, as an error in answer to a single call does. A batch of several methods gets none.application/jsonwhose body does not parse (empty, or a truncated page) is kept as text. Before, parsing it threw aSyntaxErrorbefore anHttpErrorwas built, so the status never reachedisConnectionErrorand the call failed whatever the status.EvmRpcClient.isTraceStateError:insufficient funds for gas,nonce too low/nonce too highandintrinsic gas too loware retried for calls that replay transactions already in a block:debug_traceBlockByHash,debug_traceBlockByNumber,debug_traceTransaction,trace_block,trace_replayBlockTransactions,trace_replayTransaction,trace_transaction.eth_call,eth_estimateGas,debug_traceCallandtrace_callrun a new transaction and still fail at once.rpcMethodthatRpcClientattaches to an error received in answer to a call, single or batched, or that the transport attaches to a whole-batch error. A whole-batch error of a batch of several methods stays fatal.retryInternalServerErrorsnow decides only a 500 that carries a JSON-RPC error; its doc says so.Metrics
sqd_chain_rpc_retried_errors_totalunder a newkind,wrong_state.EvmRpcClient, a bare 500 is now counted ashttp, as inRpcClient, instead ofinternal/transient.Trade-off
The dumper retries without limit, so an error misjudged as transient stalls the dump instead of restarting it.
wrong_stateis kept apart fromtransientso that a node that never recovers is visible in the metrics.Not covered
A pre-check failure inside the JSON-RPC body of an HTTP 500 is judged without the method, since the transport error carries no request, and stays fatal unless
retryInternalServerErrorsis set.Tests
util/rpc-client/src/client.connection-error.test.ts:null, JSON that is not JSON-RPC, anerrorobject or string with no envelope, an envelope with neitherresultnorerror, an empty array or an array of proxy errors;nullid, a result, a batch, JSON-RPC sent as text or bytes;http; a 500 with a JSON-RPC error, labeled as JSON or as text, fails withHttpErrorand is not counted;HttpErrorcarrying the status and the raw body; malformed JSON in a 200 still fails withRpcProtocolError;evm/evm-rpc/test/rpc.transient-errors.test.ts:eth_call,eth_estimateGas,eth_sendRawTransaction,debug_traceCall,trace_callandtrace_callMany, or with no method; other execution errors of a trace (execution reverted,insufficient funds for transfer,out of gas, a base-fee check);http; envelope-less bodies in the existing retry-kind cases replaced with JSON-RPC envelopes;wrong_state; retries go on while the node keeps failing and stop once the budget is spent; a whole-batch error of a mixed batch,eth_call, and a whole-batch error ofeth_callfail at once;http; a transient JSON-RPC error recovers astransient; a permanent JSON-RPC error fails withHttpError.rpc-client: 69 passed;evm-rpc: 370 passed, 29 skipped;tsc: clean forrpc-clientandevm-rpc(withtsconfig.test.json).🤖 Generated with Claude Code