面向开发者 / JSON-RPC
错误与限制
五个错误码承载了一切。值得好好处理的是 -32005,因为它表示一个限制而不是一个错误:同样的请求稍后就会成功。
五个错误码
| 错误码 | Value |
|---|---|
| -32602 | Invalid paramsa malformed address, block tag, filter id or topic filter |
| -32601 | Method not found or not availablean unregistered name, or one refused by design such as eth_sendTransaction |
| -32000 | Executiona revert, a decode failure, a signature failure, or a consensus rejection |
| -32005 | Limita rate limit, a full queue, a timeout, a size cap or a filter cap - every row on this page |
| -32603 | Internala write-ahead-log or coordinator failure; also every non-send error when you are on the WebSocket transport |
在运维上真正要紧的区别是 -32000 和 -32005 之间的那一个。一个执行 错误是关于你这笔交易的事实,重试改变不了任何东西;一个限制错误是关于节点当前负载的事实, 等到有空位时同样的请求就会成功。
没有 error.data
你的库无法解码 revert 原因
A revert arrives as message text - "execution reverted: 0x<returndata>" - and error.data is absent.
Libraries decode custom errors and revert strings out of error.data, so on this chain they cannot. ethers and viem will both surface the raw message instead of a decoded error. If you need the reason, parse the hex out of the message yourself and decode it against your own ABI.
差异那一页写了变通办法。
Sending a transaction
| 限制 | 值 | 变量 | 越界时 |
|---|---|---|---|
| Raw transaction sizechecked on the hex string BEFORE decoding, so an oversized transaction is a limit error rather than a decode error | 128 KiB | 编译期 | -32005 |
| Admission queuequeued transactions across all senders | 4,096 total | ADMISSION_CAPACITY | -32005 "sequencer admission queue is full" |
| Per sendercompile-time, so one sender cannot fill the queue with unfillable nonces | 64 | 编译期 | -32005 |
| Execution waitthe coordinator's own deadline is 5 s; the call waits until the transaction executes or this expires | 6 s | 编译期 | -32005 "transaction timed out waiting for execution" |
| Per execution batchMAX_ADMIT_PER_BATCH - a throughput mechanism, not a caller-visible limit | 512 | 编译期 | - |
Expensive reads
| 限制 | 值 | 变量 | 越界时 |
|---|---|---|---|
| Token bucket burstguards eth_call, eth_estimateGas and eth_getLogs together | 256 | HEAVY_READ_BURST | -32005 "rate limit exceeded for expensive read methods" |
| Refill rateprocess-wide and shared by every caller - explicitly a backstop, not per-client limiting | 128/s | HEAVY_READ_PER_SEC | - |
| eth_getLogs spana span of 5,000 or more is refused outright | under 5,000 blocks | 编译期 | -32005 "log block range is too wide" |
| eth_getLogs matchesnarrow the filter or walk the range in windows | 10,000 | 编译期 | -32005 "eth_getLogs matched too many logs" |
The HTTP listener
| 限制 | 值 | 变量 | 越界时 |
|---|---|---|---|
| Connections | 512 | RPC_MAX_CONNECTIONS | - |
| Request bodythe public vhost caps a request at 1 MiB before this applies, and 1 MiB of JSON-RPC batch is already thousands of calls | 2 MiB | RPC_MAX_REQUEST_BYTES | - |
| Response body | 16 MiB | RPC_MAX_RESPONSE_BYTES | - |
| Batch lengthsplit a larger batch client-side | 32 | RPC_MAX_BATCH | - |
| Keep-aliveTCP_NODELAY is on | 30 s | RPC_KEEP_ALIVE_SECS | - |
Filters
| 限制 | 值 | 变量 | 越界时 |
|---|---|---|---|
| Filters per node | 1,024 | MAX_FILTERS | -32005 "filter limit reached" |
| Buffer per filterthe OLDEST entries are trimmed when you stop polling, so a slow poller loses the beginning of its backlog rather than the end | 1,024 entries | MAX_FILTER_BUFFER | - |
| Idle expirymeasured since the last poll, and expiry is silent - the next poll answers -32602 "filter not found" | 300 s | FILTER_TTL_SECS | -32602 |
两个不是配置的值
MIN_GAS_PRICE (1 wei) 和 EXECUTION_SPEC (Cancun) 看起来像设置项,而它们是刻意做成编译期常量的。
Both are compile-time constants rather than environment variables, and that is a correctness requirement rather than an oversight. Either one made operator-tunable would let a replica reject or re-price a transaction the leader had accepted, and derivation would halt on the divergence. Pinning the hardfork also means a revm upgrade cannot silently change gas accounting underneath an already-settled chain.
把限制处理好
这里没有按客户端计的限流,也没有剩余预算响应头,所以客户端没法从一个信号里自我节流,它必须 在构造上就守规矩。有三件事要紧:
- 在
-32005上退避,不要立刻重试。重读令牌桶是所有调用者共享的,所以一个紧凑的重试循环是让它对包括你自己在内的所有人都保持 空桶的最快方式。 - 把你的
eth_getLogs范围切成窗口,控制在 5,000 个区块以下,并预期 10,000 条的匹配上限。在一条大约保留两分钟区块的链上, 你最先撞上的实际限制是保留期而不是跨度。 - 把批量请求控制在 32 个以内。超过之后整个批量会被拒绝,而不是被截断。
// RPC_URL: https://rpc.picklechain.xyz on the public testnet, or a node of your own.
async function call(body, attempt = 0) {
const res = await fetch(RPC_URL, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body),
});
const json = await res.json();
// -32005 is a limit, not a mistake: the same request works later.
if (json.error?.code === -32005 && attempt < 5) {
await new Promise((r) => setTimeout(r, 2 ** attempt * 250));
return call(body, attempt + 1);
}
return json;
}