A full node answers questions about recent state. An archive node answers them for any block back to genesis. So eth_call, eth_getBalance, eth_getStorageAt and eth_getCode with an old block number need archive data, and debug_* and trace_* calls on old transactions need it too, plus a node that exposes those methods. Everything at latest works on a full node, and on Geth and Reth full nodes so do block lookups by number.
The catch is that “recent” is not one number. It is 10,064 blocks on a Reth full node and 262,144 on an Erigon one, and a provider can change it. This guide shows which calls fail and the exact error messages we saw. It also shows how to test an endpoint in a minute. For the conceptual basics of node types, see What is a Blockchain Node?.
The short answer
Sort every call you make into one of four groups:
- Needs historical state.
eth_call,eth_getBalance,eth_getStorageAt,eth_getTransactionCountandeth_getCodewith a block number older than the node’s state window. On a full node these fail. - Needs historical state and trace support.
debug_traceTransaction,debug_traceBlockByNumber,trace_transactionandtrace_blockon old blocks. They replay the transaction, so they need the state just before it, and the node must expose the method. - Needs history, not state.
eth_getLogsandeth_getTransactionReceiptover old ranges. They do not touch state, but a node that pruned old receipts cannot answer them. - Works on a full node. Anything at
latestor a recent block. Geth and Reth full nodes also serve old blocks by number witheth_getBlockByNumber, but Erigon’s default full mode prunes old blocks, so it does not. Lookups by transaction hash can also be inconsistent: a provider with several backends may find a transaction on one and returnnullon another.
Two cautions. Providers set their own limits, so a “full node” at one provider keeps more than at another. And a method that is missing or gated by plan is not the same thing as missing archive data. The error text tells you which one you have.
How much history a full node keeps
A full node verifies every block and keeps the recent state. Older state is dropped to save disk, and (per ethereum.org) a node can rebuild it by re-executing past transactions, which is slow. In practice most providers simply do not offer that. The defaults below come from each client’s own documentation, read on 22 October 2026:
- Geth. A fresh database uses the path scheme, where
--history.statedefaults to 90,000 blocks (0keeps the whole chain). The often-quoted figure of 128 blocks comes from Geth’s sync-modes page (about 25.6 minutes of history at 12 seconds per block) and from the older hash scheme. Tracing in Geth still re-executes at most 128 ancestor blocks, a fixed limit, and Geth’seth_calldocs still say 128 too, so test your endpoint instead of assuming. A Geth archive uses--history.state=0 --gcmode archive --syncmode full, and historical state becomes readable only after indexing finishes, about 30 hours on mainnet according to the Geth docs. - Reth. Archive mode is the default. A full node keeps a 10,064-block historical state window. Reth’s docs say pruning is destructive, so you cannot get the data back without a resync.
- Erigon. The default
fullmode keeps state and block data within the last 262,144 blocks (about 36 days, docs updated 19 October 2026). Older blocks, receipts and state history are pruned, so a full node cannot serve queries against them. - Nethermind. It separates the two kinds of history. One setting governs historical state (what answers
eth_call,eth_getBalanceandeth_getStorageAtat old blocks). Another governs historical blocks and receipts (what answerseth_getTransactionReceiptandeth_getLogs). A full archive answers state and receipt queries at every height from genesis.
These are defaults. A provider that runs Reth can keep a wider window, and one that runs Geth can turn on archive mode, so the client name alone does not tell you what you get.
We also measured one public Ethereum endpoint (rpc.flashbots.net, client not confirmed by its operator). On 22 October 2026 it answered eth_getBalance down to 10,066 blocks behind the head and failed at 10,067, which fits Reth’s documented 10,064 window. On 23 October 2026 its own error listed an available range of 26241978 to 26252042, a span of exactly 10,064 blocks.
Calls that fail without archive data, and the errors you see
Every client words the failure differently. Match your error against this list, and always run the control first: the same call with latest. If latest fails too, you have a connection, key or method problem and not an archive problem.
Messages measured on public Ethereum endpoints
We sent eth_getBalance for block 1,800,000 (from 2016) on 22 October 2026, and for block 16 on 23 October 2026:
- Reth style, code
-32603:state at block #1800001 is pruned. The number in the message is the requested block plus one. Measured onrpc.flashbots.netandapi.zan.top. - Reth style, newer wording, code
-32603:insufficient changesets to revert to block #16. Available changeset range: 26241978..=26252042. Measured onrpc.flashbots.net. It is useful because it tells you the range the node still has. The wording varies by backend: the same endpoint also answered a block 16 request withstate at block #17 is pruned, so do not match on one string. - Geth path scheme style, code
-32000:historical state <state root> is not available. Measured oneth.meowrpc.comandapi.zan.top. The hash in the message is the state root of the block you asked for, and the text matches Geth’s source for a node that is not running as an archive. - Provider gating, code
-32602:Archive requests require a personal token. Measured onethereum-rpc.publicnode.com. This is a policy of the provider, not a property of the node.
Reth’s eth_getCode is documented as unrestricted on a full node, yet rpc.flashbots.net returned the pruned error for it as well. Do not count on eth_getCode working far back.
Messages from the client source
We did not trigger these ourselves. They come from the clients’ source code, so the exact text can change between versions:
- Geth hash scheme:
missing trie node <hash> (path <path>). - Geth tracing:
required historical state unavailable (reexec=128). - Geth path scheme while indexing is unfinished:
state histories haven't been fully indexed yet. - Nethermind, code
-32002:No state available for block <hash> (number). - Erigon: an error naming the requested block and the block history is available from.
Messages we saw from different chains
On 23 October 2026 we asked BoltRPC chains for eth_getBalance at a block 300,000 behind the head and at block 16. Five chains answered the first and refused the second, each in its own words:
- Arbitrum:
missing trie node. - Avalanche:
block not found. - Mantle:
-32801,no historical RPC is available. - zkSync Era:
-32602,Block with such an ID is pruned. - OP Mainnet:
-32603,no state found for block.
Messages that are not archive errors
When we asked public endpoints for a block that does not exist yet (block 0x7fffffff), they answered with different messages: header not found, block not found: 0x7fffffff, unsupported block number and Unknown block number. The wording differs by client and provider, but all of them mean the block is not there, not that old data is missing.
The wording is not consistent across chains, though: Avalanche used block not found for an old, pruned block. This is why the control matters. Ask for the same block on a block explorer first, then ask for it on a recent block you know exists.
eth_getLogs: not state, but still history
eth_getLogs does not need historical state. It needs the receipts and log index for the block range, and a node that pruned those cannot answer. On rpc.flashbots.net (22 October 2026) a recent five-block range returned logs. An old range, with or without an address filter, returned code 4444, pruned history unavailable. On the same endpoint eth_getTransactionReceipt for a 2016 transaction returned null, while eth_getBlockByNumber for its block returned the block.
The clients differ in how they behave:
- Reth full node:
eth_getLogsandeth_getBlockReceiptswork only for the last 10,064 blocks. - Erigon full node: an address or topic filtered
eth_getLogscan miss matches older than 262,144 blocks. Read this one carefully: it is not guaranteed to be an error. - Nethermind: a range covering pruned heights returns an error instead of fewer logs.
- Geth: keeps all block history by default (
--history.chainisall) and maintains a log search index for the last 2,350,000 blocks by default (about a year).
If your indexer needs the full history of a contract, test with an old range and check that you get an error or real logs, not an empty array. For chunking, retries and reorg handling see Production eth_getLogs Pipeline.
Trace and debug methods
Tracing exists in two families. debug_* (debug_traceTransaction, debug_traceCall, debug_traceBlockByNumber) is Geth style and takes tracer options such as callTracer. trace_* (trace_transaction, trace_block, trace_filter) is the OpenEthereum style that Erigon, Reth and Nethermind implement. Geth documents the debug namespace and no trace namespace. Erigon, Reth and Nethermind document both.
Both families replay the transaction. To do that the node needs the state at the parent block, so tracing an old transaction needs archive state, on top of the method being enabled. Reth lists every debug_trace* and trace_* call as “only for the last 10064 blocks” on a full node, and Erigon says the calls work as long as the blocks have not been pruned.
A request looks like this (replace the hash with a transaction on the chain):
curl -s -X POST -H 'Content-Type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"debug_traceTransaction","params":["YOUR_TX_HASH",{"tracer":"callTracer"}]}' \
https://endpoints.boltrpc.io/rpc/YOUR_API_KEY/base
The two families return different shapes. We ran both on 22 October 2026 against a public archive endpoint for the first transaction in Ethereum block 1,800,000. debug_traceTransaction with callTracer returned one nested call object:
{"from":"0xea674fdde714fd979de3edf0f56aa9716b898ec8","gas":"0x7530","gasUsed":"0x5208","to":"0x264ab7458bd35689ce67b12fa6d66fe68dd26db0","input":"0x","value":"0xefc5804161b6714","type":"CALL"}
trace_transaction returned a flat array, one entry per call, with traceAddress and subtraces fields to rebuild the tree.
Having archive data does not guarantee you can trace. Public providers often gate debug_* and trace_* by plan. We saw Method not available on this plan and Only core evm requests are allowed on endpoints that answered plain state reads. That is provider policy and not a node error.
Tracing also costs more than a plain read. On BoltRPC a trace call weighs more request units than eth_call; see How BoltRPC Request Units Work and pricing for the current weights.
How big an archive node is in 2026
Older articles quote 12 TB or more for an Ethereum archive node. Those figures come from before the newer storage layouts. Current client documentation gives a different picture, and every number below carries its date:
- Erigon 3: 2.25 TB for an archive node (measured as of 17 September 2026), against 534.94 GB for a full node. The receipts cache, on by default from 3.7, adds about 441 GB on top.
- Reth (Storage V2): 2.31 TB for an archive node, measured on disk at block 24,396,823 in February 2026. The legacy layout took 2.99 TB. A Reth full node took 1.02 TB.
- Nethermind: about 2.2 TB on disk for the full mainnet archive snapshot taken at block 26,032,570 (22 September 2026).
- Geth, path scheme: around 2 TB for full flat state history, or about 6.5 TB if it also stores the historical trie data (Geth docs, edited 24 February 2026). The older hash-based archive can exceed 20 TB.
- The old figures: Geth’s sync-modes page says nearly 12 TB (September 2022) and Nethermind’s system requirements page says at least 14 TB (as of July 2023). ethereum.org still says more than 12 TB for most clients and 3 TB to 12 TB overall (April 2026).
Disk is only part of it. The Erigon docs recommend a 4 TB disk for a 2.25 TB archive, and syncing takes days: Geth’s path archive takes around 2 weeks, while ethereum.org says Erigon can do a full archive sync in under 3 days. Erigon’s own hardware page reports about 14 hours 20 minutes for an Ethereum archive sync (Erigon 3.6.1, September 2026, download capped at 400 Mbps, a single sample). For the build-or-buy side, see Run Your Own Ethereum Node vs RPC Provider.
Check whether an endpoint is archive
The fastest test is the same eth_getBalance call at three points: latest, 300,000 blocks behind the head and block 16. Replace the chain slug with the one you use (here base).
curl -s -X POST -H 'Content-Type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"eth_getBalance","params":["0x0000000000000000000000000000000000000000","0x10"]}' \
https://endpoints.boltrpc.io/rpc/YOUR_API_KEY/base
A result means the endpoint has state at block 16. An error object tells you what is missing. To run all three checks at once, save this as probe.mjs and run it with RPC_URL=<your endpoint> node probe.mjs:
const RPC_URL = process.env.RPC_URL; // https://endpoints.boltrpc.io/rpc/YOUR_API_KEY/base
const ADDRESS = '0x0000000000000000000000000000000000000000';
async function rpc(method, params) {
const res = await fetch(RPC_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }),
});
return res.json();
}
async function balanceAt(block) {
const out = await rpc('eth_getBalance', [ADDRESS, block]);
return out.error ? `error ${out.error.code}: ${out.error.message}` : 'ok';
}
const head = parseInt((await rpc('eth_blockNumber', [])).result, 16);
const behind = '0x' + Math.max(0, head - 300_000).toString(16);
console.log('latest :', await balanceAt('latest')); // control: must be ok
console.log('300,000 behind :', await balanceAt(behind));
console.log('block 16 :', await balanceAt('0x10'));
Read the three lines like this:
latestfails: stop. The problem is the key, the URL or the method, not archive data.latestand 300,000 behind answer, block 16 does not: the endpoint keeps recent history only.- All three answer: the endpoint has state back to at least block 16, which is what you want for old-block reads.
We ran this probe on two public Ethereum endpoints on 23 October 2026: one failed at 300,000 behind and at block 16, the other answered all three.
Read the node’s own message in viem and ethers
Libraries hide the real reason by default. In viem, err.shortMessage is generic (An internal error was received. on a pruned Reth-style endpoint) and the node’s text is in err.details:
import { createPublicClient, http, formatEther } from 'viem';
import { base } from 'viem/chains';
const client = createPublicClient({ chain: base, transport: http(process.env.RPC_URL) });
try {
const balance = await client.getBalance({
address: '0x0000000000000000000000000000000000000000',
blockNumber: 16n,
});
console.log(`balance at block 16: ${formatEther(balance)} ETH`);
} catch (err) {
console.log('failed:', err.shortMessage); // generic, hides the node's reason
console.log('details:', err.details); // the node's own text
}
In ethers v6 the same error arrives as UNKNOWN_ERROR with the message could not coalesce error, and the node’s reason sits inside err.info.error:
import { JsonRpcProvider, formatEther } from 'ethers';
const provider = new JsonRpcProvider(process.env.RPC_URL, 8453, { staticNetwork: true });
try {
const balance = await provider.getBalance('0x0000000000000000000000000000000000000000', 16);
console.log(`balance at block 16: ${formatEther(balance)} ETH`);
} catch (err) {
console.log('failed:', err.shortMessage ?? err.message, '| code:', err.code);
console.log('node error:', JSON.stringify(err.info?.error ?? err.error ?? null));
}
Log the node’s text, not the library’s summary. It is the only part that says “pruned”, “not available” or “plan”.
Archive and trace on BoltRPC
Archive depth and trace support on the shared endpoints are properties of each chain’s node pool, not of your plan. Every plan gets what the chain offers, at the published weights. Where a shared pool keeps recent state only, archive access can be built as a custom setup on request. The one exception is three unbounded state-iteration methods (debug_accountRange, debug_storageRangeAt and debug_dumpBlock), which are enabled per account on request from the Business plan upward. See pricing.
Here is what we measured on 23 October 2026 with a BoltRPC key, using eth_getBalance for the zero address. Capabilities change as we upgrade pools, so check the chain’s page under /networks (for example Base) before you build on one.
State at block 16 answered (historical state from genesis):
- ApeChain
- Base
- Celo
- MegaETH
- Plasma
- Robinhood Chain
- Scroll
- Sonic
State 300,000 blocks behind the head answered, block 16 did not (recent history only):
- Arbitrum
- Avalanche
- Mantle
- zkSync Era
- OP Mainnet
Ethereum mainnet: the shared BoltRPC endpoint serves recent state. A request for block 16 and one for a block 300,000 behind the head both returned -32000 with historical state <state root> is not available. Archive access on Ethereum is a custom setup that BoltRPC builds on request: contact us with the depth and methods you need. Ethereum trace_block and debug_traceBlockByNumber returned -32601 (method not available) in the same test.
Trace and debug results:
trace_blockworked on Sonic and MegaETH.debug_traceBlockByNumberwithcallTracerworked on Base and Arbitrum for a recent block, anddebug_traceTransactionworked on a recent Base transaction.
Historical state and historical tracing are separate. Base answered eth_getBalance at block 16, yet tracing an old Base block can return 4444 with pruned history unavailable: requested 1048576, earliest available <block>. When we called debug_traceBlockByNumber for block 1,048,576 twelve times, ten calls returned that error (with two different earliest blocks, depending on the backend) and two succeeded. debug_traceTransaction for a transaction from that block returned transaction not found in 11 of 12 calls. Arbitrum answers debug_traceBlockByNumber and keeps recent state only. So test the exact call you need at the exact depth you need, more than once, and not only with eth_getBalance.
FAQ
What is the difference between an archive node and a full node?
A full node verifies the whole chain but keeps state only for recent blocks, so it can answer eth_call or eth_getBalance for recent blocks and latest. An archive node keeps state at every block back to genesis, so the same calls work for any block. How recent “recent” is depends on the client and the settings: 10,064 blocks on a Reth full node, 262,144 on Erigon.
Does eth_call need an archive node?
Only when you pass an old block. eth_call at latest or a recent block works on a full node. Geth’s eth_call documentation says it is not possible to execute calls against blocks older than 128 unless the node is an archive node. If your reads are always at latest, you do not need archive data.
Does debug_traceTransaction need an archive node?
Yes for old transactions. Tracing replays the transaction on the state just before it, so the node needs that state and has to expose debug_traceTransaction. A full node can trace very recent transactions. Geth re-executes at most 128 ancestor blocks, and a Reth full node traces only the last 10,064 blocks.
What does “historical state is not available” mean?
It is the Geth path-scheme error for a state read on a block older than the node keeps, and it includes the state root of the block you asked for. It means the node has the block but not its state. Retry on an archive endpoint, or switch to a chain whose pool keeps historical state. If the same call with latest also fails, the problem is not archive data.
How do I know if my RPC endpoint is archive?
Call eth_getBalance at latest, at a block 300,000 behind the head and at block 16, and compare. If all three answer, the endpoint has state back to at least block 16. The probe script above runs all three, and the error text tells you whether the cause is pruning, a missing method or a plan limit.
Pick the endpoint that matches the calls you make
Check the three groups of calls in your code: state reads at old blocks, history reads such as eth_getLogs, and traces. A full node covers everything at latest. For the rest, pick a chain whose page under /networks lists the depth you need, then run the probe above with your own key.
Start your free 14-day trial, no credit card required: dashboard.boltrpc.io
