An xOneRS node meters its JSON-RPC with a token bucket. Each call costs units by its class, and when the bucket is empty the node answers HTTP 429 with error -32005 and a retry delay. We hit this ourselves on 2026-11-15: polling eth_getBlockByNumber("latest") about 50 times a second on a net2040 follower got 1,246 refusals in two minutes, and polling 10 times a second got none. This post gives the numbers from the source and shows how to follow the chain without hitting the limit. The bucket size is fixed in code today; issue #1240 asks for flags.

How does the bucket work?

From Limits::default in crates/xone-rpc/src/server.rs and docs/rpc/methods.md:

REFERENCE TABLEScroll to explore all columns →
Setting Value
Burst 400 units
Refill 200 units per second
Class C0 (e.g. eth_blockNumber, eth_chainId) 1 unit, 2 s deadline
Class C1 (e.g. eth_getBlockByNumber, eth_getBalance, eth_call) 5 units, 10 s deadline, at most 32 at once
Class C2 (e.g. eth_getLogs, eth_estimateGas, eth_getBlockReceipts) 20 units, 10 s deadline, at most 8 at once
Class C3 (debug_trace*, trace_*) 100 units, 30 s deadline, at most 2 at once

So the sustained rate is about 200 eth_blockNumber, 40 eth_getBlockByNumber, 10 eth_getLogs or 2 traces per second. Our 50 calls per second of a C1 method needed 250 units per second, more than the refill.

What does a refusal look like?

HTTP status 429 Too Many Requests, with a JSON-RPC body:

{"jsonrpc":"2.0","id":1,"error":{"code":-32005,"message":"limit exceeded","data":1}}

data is the retry delay in seconds, and the HTTP reply carries it as Retry-After. The same code also answers when a class is at its concurrency limit or the node is busy. A client should wait the given delay, not retry at once.

How should a client follow the head?

  • Subscribe instead of polling. eth_subscribe("newHeads") over WebSocket pushes each new block once; newFinalizedHeads pushes only final ones. See streaming chain events.
  • If you must poll, poll the cheap method. eth_blockNumber costs 1 unit; fetch the block only when the number changes. A block comes about every 2 seconds, so polling more than a few times a second gains nothing.
  • Space your calls. At one C1 call every 0.1 s we saw no refusal over 150 s.
  • Handle null. On the build we tested, eth_getBlockByNumber("latest") answered null 3 times in 1,479 calls (issue #1229); retry rather than treat it as "no chain".

Can an operator raise the limit?

Not yet: the burst, refill and class concurrency are fixed defaults, while other RPC limits already have flags. Issue #1240 asks for --rpc.bucket.burst, --rpc.bucket.rate and per-class concurrency. Until then, put a cache or a second node behind the load balancer for heavy read traffic, and see the RPC provider checklist.

Frequently asked questions

Why does my xOne RPC endpoint return HTTP 429?

The rate bucket is empty: more than 200 units per second over time, after a 400-unit burst. Each eth_getBlockByNumber costs 5 units.

What does error -32005 mean on xOne?

"Limit exceeded": rate bucket, class concurrency or a busy node. data is the retry delay in seconds.

How many eth_getLogs calls per second can an xOne node take?

About 10 per second sustained, each costing 20 units, and at most 8 at once.

What is the best way to get new XDC blocks from xOne?

Subscribe to newHeads over WebSocket. Polling eth_blockNumber every second is the cheap alternative.

Sources