xOneRS bounds every RPC request before it does any work. A batch holds at most 100 items, a body at most 5 MiB and a response at most 20 MiB. Each connection and each transport has a rate bucket, and a rejected call gets -32005. Only the namespaces you list are served; any other method answers -32601. With a JWT secret, every HTTP and WebSocket request needs a valid token before it is read. Each rule below has a named test in crates/xone-rpc/tests/rpc.rs.
For the method list and parity, see the xOne RPC surface. For the parity numbers, see RPC parity in numbers.
Which namespaces are served?
HTTP and WebSocket serve eth,net,web3 by default (--http.api, --ws.api). IPC serves all namespaces and is created with mode 0600. An unknown namespace in the list, or *, refuses the start; admin and debug are served only when listed (transport-exposure.md). A method outside the served list answers -32601.
Since PR #1078 (2026-11-15), HTTP and WebSocket can serve native TLS: --http.tls.cert and --http.tls.key (and --ws.tls.cert, --ws.tls.key) load PEM files at start, and --http.tls.clientca or --ws.tls.clientca makes clients present a certificate from that CA. An invalid certificate or key refuses the start. Since PR #1099, --rpc.acl maps each JWT principal to the methods it may call. Neither is in the v0.1.0 release; there, use a TLS reverse proxy.
Tests: unknown_namespace_is_refused_and_defaults_hide_privileged_methods, http_refuses_methods_outside_its_list_and_a_wrong_host, out_of_scope_namespaces_are_method_not_found, ipc_bind_is_private_refuses_non_sockets_and_live_sockets.
How large can a request be?
| Limit | Value | Flag or config key |
|---|---|---|
| Batch items | 100 | --rpc.batch-request-limit |
| Request body or WebSocket message | 5 MiB | limits.rpc_body_bytes |
| Response, single or batch | 20 MiB (-32003 above it) |
--rpc.batch-response-max-size |
A batch answers in request order. Read-only members run at most 4 at a time; every other member runs alone and in order (scope-adr-008.md). Tests: batch_of_100_keeps_order_and_ids_and_101_is_refused, batch_answers_stop_at_the_response_byte_budget, websocket_shares_the_http_body_and_batch_limits, object_and_array_ids_are_refused_without_dispatch.
How is load bounded?
- Buckets. One per connection and one per transport: 400 burst, 200 per second. A batch costs the sum of its parts. A reject is
-32005 limit exceeded, with the seconds until the bucket holds the cost. - Classes. Methods are in classes C0 to C3, with concurrency 32, 8 and 2 for C1, C2 and C3 and deadlines of 2, 10, 10 and 30 seconds. Under load shedding, C2 and C3 answer
-32005withdata: "node busy". - Connections. HTTP: 256 connections, 64 in flight, 128 waiting (the next is
429withRetry-After). WebSocket: 128 connections, 8 in flight each. IPC: 16 connections.
Tests: quota_bucket_rejects_with_32005_and_a_retry_hint, load_shedding_rejects_c2_and_c3_with_node_busy_and_keeps_c0_c1, class_concurrency_is_bounded, http_serves_requests_and_429s_on_rejection, http_closes_slow_heads_and_stalled_bodies, get_logs_rejects_a_range_that_overflows_the_budget.
How do I protect a remote endpoint?
- Keep
--http.vhosts(defaultlocalhost),--http.corsdomainand--ws.origins(default none) narrow. - Set
--rpc.jwtsecret <file>(32 bytes hex). HTTP and WebSocket then require an HS256 bearer token, checked before the body is read. IPC is not affected. - Remote privileged access needs three explicit choices: a non-local bind address,
adminordebugin the list, and a JWT secret. No default opens it.
Tests: http_with_a_jwt_secret_refuses_every_bad_credential_before_dispatch, websocket_with_a_jwt_secret_needs_the_token_on_the_upgrade, websocket_refuses_methods_outside_its_list_and_a_wrong_origin, http_cors_preflight_and_responses_follow_corsdomain.
How do WebSocket subscriptions behave?
eth_subscribe works on WebSocket and IPC. A subscriber whose queue is full is dropped, never waited for. Closing a connection removes all its subscriptions. There is no replay: events published while a client is away are not delivered. Logs of blocks removed by a reorg are published again with removed: true (scope-adr-008.md). A client that never answers pings is closed.
The earlier defect where newHeads and logs returned an id but delivered nothing (issue #122) is closed. Tests: websocket_subscribes_receives_heads_and_cleans_up_on_close, subscriptions_follow_the_transport_policy_and_are_bounded, websocket_message_bound_covers_subscriptions_and_fragments, websocket_client_that_never_answers_pings_is_closed.
How do other clients describe RPC limits?
| Client | What its article states | xOne |
|---|---|---|
| erigon | --rpc.blockrange.limit, --rpc.logs.maxresults, --rpc.max.concurrency added in 3.4, as stated in Erigon 3.4, 2026-04-28 |
per-class concurrency, and --rpc.rangelimit and --rpc.logs.maxresults since PR #1074, with tests |
| geth | --rpc.rangelimit in v1.17.0, as stated in the v1.17.0 release notes, 2026-02-17 |
--rpc.rangelimit (default 5,000 blocks) since PR #1074; a larger range is rejected before any block is read |
Frequently asked questions
What is the batch limit of the xOne JSON-RPC?
100 items. A 101st item refuses the batch. The limit is --rpc.batch-request-limit.
What does -32601 mean on xOne?
The method is not served on this transport: either it is outside the namespaces you listed, or it is out of scope.
What does -32005 mean on xOne?
The rate bucket or the class limit rejected the call. data gives the seconds to wait, or "node busy" under load shedding.
Do WebSocket subscriptions replay missed events?
No. Events published while a client is away are not delivered. A client that falls behind is dropped.
Sources
This article describes the source and evidence at its review date. Check the linked repository for current implementation and qualification status.
Explore the engineering evidenceEdit this page on GitHub opens the Markdown source (content/blog/rpc-exposure-safely/index.md). GitHub may ask you to sign in. Report a correction opens a prefilled GitHub issue for this page.