Ethereum RPCエラーを層別に直す:4001・429・-32602・nonce・revert
Ethereum RPCエラーをwallet provider、HTTP、JSON-RPC、node、transaction、EVMへ分類。viemのcause chainとraw responseを対応させ、安全な再試行と修正手順を解説します。

4001、429、-32602、nonce too low、execution revertedを、すべて「RPCエラー」として同じ再試行へ流してはいけません。発生した場所が違えば、直す対象も違います。
最初に保存するのは、method、paramsの形、chain ID、block、HTTP status、JSON-RPCのcode・message・data、viemのerror名とcause、transaction hashです。API key、cookie、署名済みraw transaction、個人情報は保存しません。
この記事では、wallet provider、HTTP transport、JSON-RPC protocol、nodeまたはgateway policy、transaction validation、EVM executionへ分けます。2026-08-31時点のviem 2.56.0とFoundry / Anvil 1.8.0を使い、外部walletやpublic RPCを使わないローカル環境で12種類の応答とcustom errorを確認しました。
エラーを7層へ置く
画面へ最後に表示されたmessageは、もっと内側のerrorを包んでいることがあります。次の順で、最初に失敗した境界を探します。
| 層 | 代表的な症状 | 最初に保存する証拠 | 主な次の行動 |
|---|---|---|---|
| app / library | ChainMismatchError、ABIや型の不一致 |
action名、library version、入力の形 | chain、ABI、引数を直す |
| wallet provider | 4001、4100、4200、4900、4901 |
origin、method、provider code、選択chain | user action、許可、対応methodを確認 |
| HTTP transport | DNS、TLS、timeout、429、5xx |
URLのhost、status、Retry-After、経過時間 |
待機、範囲縮小、限定的なfallback |
| JSON-RPC | -32601、-32602、-32603 |
request ID、method、params、error object | method・params修正、内側のerror確認 |
| node / gateway | -32005、archive不足、payload制限 |
client、plan、block range、message、data | range縮小、必要なnode機能を選ぶ |
| transaction validation | funds、fee、nonce、replacement | sender、nonce、balance、fee、既存hash | 同じ入力の連打を止めてstateを直す |
| EVM execution | revert、out of gas、custom error | call data、revert data、シミュレーション時のblock、receipt | selectorと引数を復号し、contract条件を直す |
codeだけで層を断定できない場合もあります。たとえば-32000はEIP-1474でinvalid inputですが、node実装はmessageへinsufficient fundsなどを入れることがあります。code、message、data、呼び出したactionを組にしてください。
最初の30秒でrequest identityを固定する
再現前に、次を一件の記録へまとめます。
- operation名と実行時刻
- RPC methodと、秘密値を除いたparamsの形
- chain ID、block numberまたはtag、対象address
- HTTP status、
Retry-After、経過時間 - JSON-RPC code、message、dataの型
- viemの最上位error名、
shortMessage、details、cause名 - transactionを送った可能性がある場合はhash、sender、nonce
methodとparamsを保存せずmessageだけを見ると、同じInvalidParamsRpcErrorでも「addressの形式」「block quantityの形式」「引数の個数」を区別できません。反対にraw headerを丸ごと保存すると、API keyやcookieを漏らす危険があります。必要なfieldを先に決め、値ではなくshapeだけ残すfieldを分けます。
wallet providerの4001・4100・4200・4900・4901
EIP-1193は、providerが返す代表的なcodeを定義しています。
| code | 意味 | 自動再試行 | 読者へ伝える内容 |
|---|---|---|---|
4001 |
userがrequestを拒否 | しない | キャンセル済み。必要なら本人がもう一度開始する |
4100 |
methodまたはaccountが未承認 | しない | originとaccountの許可を確認する |
4200 |
providerがmethod非対応 | しない | 対応確認または別の実装経路が必要 |
4900 |
すべてのchainから切断 | 接続回復後だけ | providerの接続状態を確認する |
4901 |
指定chainだけ未接続 | しない | 意図したchainを確認し、明示的に選択する |
4001を「RPCが不安定」と扱って自動でwallet popupを再表示すると、userの拒否を無視します。4200も時間経過ではmethod対応になりません。4901では、アプリが別chainへ勝手に目的を変えず、要求したchainと現在chainを表示します。
chainの値がアプリ設定とwallet clientで違うChainMismatchErrorは、providerへrequestが届く前にlibraryが止める場合があります。このときはHTTP statusを探すのではなく、設定したchain、walletが選んだchain、署名対象chainを比較します。
HTTP 429・timeout・5xxは送信結果を先に分ける
HTTP 429 Too Many Requestsは、一定時間のrequest数が多すぎることを示します。RFC 6585では、serverは待機時間をRetry-Afterで示せます。
読み取りmethodなら、Retry-Afterを優先し、上限付き指数backoffとjitterを使えます。たとえば1秒、2秒、4秒へ増やし、最大回数と全体timeoutを決めます。全clientが同時に再試行するのを避けるため、待機へ小さな乱数を加えます。
しかしeth_sendRawTransactionのtimeoutは別です。responseを受け取れなくても、nodeがtransactionを受理した可能性があります。同じ署名済みtransactionならhashを手元で導出し、まずeth_getTransactionByHashとsenderのpending nonceを確認します。別nonceや別署名を作って即送信すると、重複意図やreplacement競合を増やします。
| 状況 | 同じrequestの再試行 | 先に行う確認 |
|---|---|---|
eth_blockNumberがtimeout |
上限付きで可 | endpoint、経過時間、chain ID |
eth_getLogsが429 |
range縮小後に可 | Retry-After、from / to block、件数制限 |
eth_callが503 |
block固定後に可 | chain、block、calldata、fallbackとの差 |
eth_sendRawTransactionがtimeout |
即時は不可 | 導出hash、pending nonce、既存transaction |
| wallet署名要求がtimeout | 自動表示しない | wallet側の未完了requestとuser action |
fallback endpointを使う場合も、chain、block、method、paramsを変えません。別endpointで値が違うときのblock固定方法はEthereum RPCのlatest・archive・Multicallを比較する記事で確認できます。
JSON-RPCの-32601・-32602・-32603
EIP-1474はEthereum RPCのerror objectにcodeとmessageを要求し、JSON-RPC標準codeを採用しています。
-32601 Method not found: method名が存在しない、またはendpointが公開していない-32602 Invalid params: 引数の個数、順序、型、hex encodingなどが不正-32603 Internal error: JSON-RPC処理内の内部error
-32601と-32602は、同じbodyを待って再送しても通常は直りません。methodの綴り、clientの対応、address、quantityとdataのhex規則、block identifier、引数の順序を直します。
-32603は一時的な場合がありますが、先にraw errorのdataと内側のmessageを保存します。contract revertをgatewayがinternal errorへ包む実装もあるため、「node障害」と断定して再試行する前にrevert dataがないか確認します。
{
"jsonrpc": "2.0",
"id": 17,
"error": {
"code": -32602,
"message": "Invalid params",
"data": { "field": "params[0]" }
}
}
request IDはresponseとの対応に使います。batch responseは送信順と同じとは限らないため、配列位置ではなくIDで結合します。
node policyはgatewayとexecution clientを分ける
-32005 Limit exceeded、広すぎるeth_getLogs、古いstateへのarchive制限、payload size制限は、同じnode故障ではありません。provider plan、gateway、load balancer、execution clientのどこが返したかを記録します。
range制限ならblock範囲を分割し、重複blockをIDやlog identityで排除します。archive不足なら、同じcurrent requestが成功してもhistorical stateを読める証拠にはなりません。必要なhistory depthを明示し、対応するnodeまたはplanを選びます。
providerを切り替えるだけで万能に直るとは限りません。invalid paramsやcontract revertを別providerへ繰り返せば、同じ入力を増幅するだけです。
insufficient funds・nonce・replacementはstateを直す
transaction validationは、EVM bytecodeを実行する前に止まる層です。go-ethereum 1.17.5のsourceでも、nonce、funds、gas、fee cap、transaction poolのreplacement policyは別errorとして定義されています。
insufficient funds
sender balanceがvalue + gas limit × feeを賄えるか確認します。token残高ではなく、gasを支払うnative assetの残高です。同じtransactionを待って再送しても残高は増えません。balanceを読むblock、value、gas、max feeを揃えて再計算します。
nonce too low
指定nonceがすでに使われた、同じtransactionが取り込まれた、または別endpointのpending viewが遅れている可能性があります。latestとpendingのtransaction count、既知hash、receiptを確認します。nonceを機械的に1増やす前に、同じ意図がすでに送られていないか調べます。
replacement underpriced
同じsender・nonceのpending transactionを置き換えるには、nodeのreplacement policyを満たすfee上昇が必要です。値はclientやpool policyで変わり得るため、固定率を万能値として書きません。元transaction、replacement、同じnonce、fee field、node messageを対応させます。
transactionの入力・receipt・eventを調べる全体手順はviemで失敗transactionを調べる記事、gas estimationの境界はestimateGasが失敗する理由、pending・dropped・replacedはtransaction状態を判定する記事へ進んでください。
execution revertedはEVMの戻りdataを読む
execution revertedは、EVM executionへ到達して戻された状態です。HTTP 200のJSON-RPC errorになることも、-32603や-32000へ包まれることもあります。messageだけでなく、revert dataを保存します。
custom errorなら先頭4 bytesのselectorとABIからerror名と引数を復号できます。ローカルAnvilではexecute(3)に対してBelowMinimum(caller, 3, 7)を返し、viemでは最上位のContractFunctionExecutionErrorからcauseをたどってContractFunctionRevertedErrorと引数を取得しました。revert後にcontract stateが変わっていないことも確認しています。
revert dataの復号手順はexecution revertedとcustom errorの記事を参照してください。シミュレーションが成功しても、送信時のblock、state、sender、value、gasが変われば同じ結果とは限りません。反対にシミュレーションのrevertはreceiptではなく、transactionがbroadcastされた証拠にもなりません。
viemではshortMessage・details・causeを分ける
viem 2.56.0ではerrorがBaseErrorを継承し、読みやすいshortMessage、内側のdetails、元errorのcauseを持ちます。最上位messageを正規表現だけで分類せず、classとcause chainを使います。
import {
BaseError,
HttpRequestError,
InvalidParamsRpcError,
RpcRequestError,
} from 'viem'
try {
await client.getBalance({ address, blockNumber })
} catch (error) {
if (!(error instanceof BaseError)) throw error
const httpError = error.walk(
(candidate) => candidate instanceof HttpRequestError,
)
const rpcError = error.walk(
(candidate) => candidate instanceof RpcRequestError,
)
const invalidParams = error.walk(
(candidate) => candidate instanceof InvalidParamsRpcError,
)
audit.write({
name: error.name,
shortMessage: error.shortMessage,
details: error.details,
httpStatus: httpError?.status,
rpcCode: rpcError?.code,
rpcDataShape: shapeOnly(rpcError?.data),
decision: invalidParams ? 'fix-input' : 'review-layer',
})
}
detailsにはnode messageが入ることがありますが、秘密値を含まない保証はありません。公開logへ出す前にredactionを通します。Authorization、cookie、API key付きURL、署名済みraw transaction、private key、seed phraseは記録しません。
ローカル再現で12種類のmappingを固定した
Node 24.14.0とviem 2.56.0で、127.0.0.1の一時HTTP serverだけを使い、次を確認しました。
- provider:
4001、4100、4200、4900、4901 - transport: HTTP
429+Retry-After: 2、40ms timeout - JSON-RPC:
-32601、-32602、-32603 - node policy:
-32005 - transaction validation message:
-32000+insufficient funds
たとえば-32602はInvalidParamsRpcError → RpcRequestError → raw error object、HTTP 429はHttpRequestError、4001はUserRejectedRequestError → RpcRequestError → raw error objectになりました。公開再現JSONで、sanitized request、raw response、viem error chain、再試行分類を確認できます。
Foundry / Anvil 1.8.0、Solidity 0.8.36、Prague EVMではcustom errorとrollbackを3ケース確認しました。外部wallet、public RPC、real account、外部署名、実資産は使っていません。
再試行・backoff・fallbackの判断
- method、params shape、chain、block、request IDを固定する
- transaction送信済みの可能性があるか分ける
- HTTP statusとJSON-RPC error objectを別fieldへ保存する
- viemの最上位classとcause chainから失敗層を特定する
- user拒否、unsupported、invalid params、funds、nonce、revertは原因を直す
- 429、timeout、5xx、internal errorは、読み取りだけ上限付きで再試行する
- writeの結果が不明ならhashとnonceを調べ、重複送信を防ぐ
- fallbackでもchain、block、method、paramsを保ち、応答差を記録する
自動再試行の対象をcode一覧だけで決めず、methodの副作用と「serverが受理した可能性」を判定してください。eth_callとeth_sendRawTransactionは、同じtimeoutでも扱いが違います。
support logの最小field
| field | 保存例 | 秘密値への対応 |
|---|---|---|
operation |
load-position |
内部画面名を一般化 |
method |
eth_call |
保存可 |
sanitizedParamsShape |
{to,dataBytes,blockTag} |
calldata全文は必要時だけ限定保管 |
chainId / block |
1 / finalized |
保存可 |
httpStatus / retryAfter |
429 / 2 |
保存可 |
rpcCode / rpcMessage |
-32602 / Invalid params |
dataに個人情報がないか確認 |
viemErrorName |
InvalidParamsRpcError |
versionと組にする |
causeNames |
class名の配列 | message全文より先に保存 |
transactionHash |
既知の場合のみ | raw signed transactionは保存しない |
attempt / elapsedMs |
2 / 2140 |
再試行の集中を発見する |
decision |
fix-input |
実行した分岐を残す |
RPCや監視serviceを比較する場合も、この分類と計測条件を広告・sponsor表記から分離します。特定providerへの切替を、invalid input、nonce競合、contract revertの万能解決策として扱いません。
確認チェックリスト
- methodとparams shapeを保存した
- chain ID、block、addressを固定した
- HTTP statusとJSON-RPC codeを別fieldで読んだ
- viemの
shortMessage、details、cause classを確認した - 4001を自動で再表示していない
- 429では
Retry-Afterと範囲制限を確認した - invalid paramsを待機だけで再送していない
- transaction送信結果が不明ならhashとnonceを先に調べた
- insufficient funds、nonce、replacement、revertを別層へ分けた
- fallbackでもchain、block、method、paramsを変えていない
- API key、cookie、署名済みraw transaction、秘密鍵をlogへ残していない
結論は、error messageをそのまま再試行条件にせず、raw responseとviem cause chainを対応させ、失敗した層とmethodの副作用を決めてから次の行動を選ぶことです。入力を直すerror、user actionを待つerror、限定的に再試行できるerrorを分ければ、無駄なrequestと重複transactionを減らせます。
確認した一次情報
- EIP-1193 Ethereum Provider JavaScript API確認日: 2026/08/31
- EIP-1474 Ethereum Remote Procedure Call Specification確認日: 2026/08/31
- Ethereum JSON-RPC API確認日: 2026/08/31
- JSON-RPC 2.0 Specification確認日: 2026/08/31
- RFC 6585 429 Too Many Requests確認日: 2026/08/31
- RFC 9110 idempotent methods確認日: 2026/08/31
- viem errors glossary確認日: 2026/08/31
- viem 2.56.0確認日: 2026/08/31
- viem BaseError source at 2.56.0確認日: 2026/08/31
- viem request error mapping and retry source at 2.56.0確認日: 2026/08/31
- go-ethereum 1.17.5確認日: 2026/08/31
- go-ethereum transaction validation errors at 1.17.5確認日: 2026/08/31
- go-ethereum transaction pool errors at 1.17.5確認日: 2026/08/31
- Foundry 1.8.0確認日: 2026/08/31



