Fresh Block, Stale View: Why Your Agent Can't Tell When Chain Data Is Old

October 5, 2026
9 min read

Say you ask an AI agent to pay a supplier 5,000 USDC and confirm the payment went through. The agent sends it, waits a few seconds, and checks. The server that answers the check happens to be running behind the chain, so it has no record of the transaction yet and says so. The response has no error and no warning, only a clean answer that the payment isn't there. The agent does the reasonable thing and pays again.
Both payments land. Your supplier receives 10,000 USDC, and when your team goes looking for the bug, they can't find one, because every request in the log succeeded.
That is what a stale read looks like in practice. A blockchain node can fall minutes or even hours behind the chain and keep answering in milliseconds with perfectly formed data, and most agents have no way to tell. The usual safeguards (error codes, success rates, provider health checks) all assume a bad node is a broken node. The dangerous one is working fine and simply out of date.
Agents can protect themselves with two habits: checking how old a block is before trusting it, and asking for a specific block height instead of whatever the server considers latest. This article shows how stale reads reach agents, why they're so hard to catch, and the rules that stop an agent from acting on them.
A flat line during an incident
On one network we operate, a single region's nodes fell roughly 80 blocks behind head, about 35 seconds of chain time. For the length of the incident, the chain-level success rate held at baseline and the error rate showed no spike.
Every dashboard said healthy. Every client routed to that region received half-minute-old state, and none of them had a signal to act on. If your monitoring is built on success rates and error codes, this is the incident it can't see.
Thirty-five seconds sounds small until you consider what an agent does with it. On a fast chain, it can span dozens of blocks. A price, a pool balance, or an allowance read in that window may already be wrong by the time the agent acts on it, and the agent will act with full confidence because nothing told it otherwise.
Why the stale node wins
Gateways commonly send a read request to more than one node and accept the first good answer. The design exists to beat slow nodes, and it works. It also means a node that answers quickly with old data can beat a slower node that is at head.
In a second incident, a node 41 hours behind the chain was still being accepted for fan-out requests, about 44,500 times in four hours. We confirmed it by joining every per-attempt node result to the response the client actually received, using the trace ID carried on each request. The accepted attempts showed successful status and short durations. For historical requests pinned to a specific block height, that node's answers were correct, because it had already synced those blocks. The harm landed on latest and untagged reads. To the client, those were fast, clean responses describing a chain that was almost two days out of date.
Why nobody can reproduce it
Closest-node routing makes stale reads look like user error.
A developer reports an old balance. A colleague in another region runs the same query, sees the current value, and closes the ticket. Both are right. The reporter's requests were served by stale nodes near them, and the colleague's were routed to healthy nodes somewhere else.
This is why stale-data bugs tend to get closed rather than fixed. The person investigating is often looking at a different chain state from the person who reported it, and neither has a reason to suspect the other is seeing something different. If your agent runs in one region and your debugging happens in another, you may never see what your agent saw.
Latest is a guess, an explicit height is a question
Most agent tool layers read chain state with the latest tag. That feels like asking for the current block. In practice, it asks the answering node for whatever it currently believes is the latest block, and a node that is behind will answer honestly with an old one.
An explicit block number changes the question. Instead of "what do you have," it asks "what was true at this block." A node that hasn't reached that block can't substitute an older one. It has to return an error or a null, and either of those is something an agent can detect and handle. A pinned height gives you consistency, though, and consistency is different from freshness. If the height came from a stale read, every read pinned to it will agree, and all of them will be old. The height has to come from a read that already passed the timestamp check.
That difference is the most useful single change an agent builder can make. It converts a silent failure into a visible one without adding any infrastructure.
When a stale read turns into a duplicate transaction
Staleness costs the most in write-then-read loops.
An agent sends a transaction and polls eth_getTransactionReceipt. If the poll reaches a node that is behind, the receipt comes back null. The node isn't lying. It genuinely hasn't seen the block that includes the transaction yet.
An agent that reads that null as "not mined" may rebuild the transaction and send it again. A missing receipt is weak evidence. A stronger check is eth_getTransactionCount for the sending address, on a node that passed the freshness check: if the count is greater than the transaction's nonce, a transaction at that nonce has been mined. Rebroadcasting the same signed transaction is harmless, because it carries the same hash, but the node may reply with "already known" or "nonce too low," and an agent can misread either one as a failure. Building a new transaction with a fresh nonce is how one payment becomes two.
Health checks shorten this exposure without eliminating it. In the 41-hour incident, about 92% of traffic drained off the stale node within roughly 15 minutes. The node then passed checks, was re-admitted, fell behind, and was drained again, three times in total. Each re-admission opened a new window in which clients could receive old data. That cycle is normal behavior for a multi-node system under load, and it's why an agent can't assume staleness has already been filtered out upstream.
Four rules for freshness-safe agents
These rules work with any provider.
Check the timestamp, not just the block number. A block number looks current whether it is or not. After the first read in a task, compare the block's timestamp with wall-clock time against a per-chain threshold based on that chain's block time. A gap that is routine on a slow chain is a serious lag on a fast one. If the gap exceeds the threshold, re-read or stop and report uncertainty.
Pin the block height and pass it down. When an agent chains several reads into one conclusion, latest lets each read land on a different node at a different height. The agent can combine a balance from one block with an allowance from another and reach a conclusion that was never true at any single moment. Take the height from the first read once it passes the timestamp check, and pass it explicitly to every dependent read:
json
{ "method": "eth_call", "params": [{ "to": "0x...", "data": "0x..." }, "latest"] }
becomes:
json
{ "method": "eth_call", "params": [{ "to": "0x...", "data": "0x..." }, "0x1590a2c"] }
A node that hasn't reached the pinned block returns an error or a null instead of quietly serving older state, and every read in the task describes the same moment.
Treat a null receipt as unknown. Before concluding a transaction wasn't mined, call eth_getTransactionCount for the sending address on a node that passed the freshness check. If the count is greater than the transaction's nonce, a transaction at that nonce is mined. Otherwise keep polling with backoff. If the agent rebroadcasts the same signed transaction and gets "already known" or "nonce too low," the network already has it; neither response means the send failed. Never construct a replacement transaction on the strength of a null alone. The same discipline applies to pinned reads: a null at an explicit height means the node may not have that block yet, and says nothing about whether the data exists.
Stop re-reading reads that already succeeded. Re-querying latest to double-check a result can land on a different node, so the second answer may be older than the first. The agent then sees state move backwards and tries to reconcile a contradiction created entirely by routing. If a read succeeded and passed the freshness check, keep it. Re-read only at the pinned height.
A production checklist
Before an agent reports chain state or takes onchain action, confirm that:
- Every task checks block timestamp against wall clock with a per-chain threshold.
- The block height from the first read is pinned only after it passes the timestamp check, and is passed to every dependent read.
- A null receipt, or a null at a pinned height, is handled as unknown, and mined status is confirmed with eth_getTransactionCount from a fresh node.
- Transactions are never rebuilt with a new nonce because of a null receipt or an "already known" or "nonce too low" response.
- Successful, fresh reads are not re-queried against latest.
- Stale-data reports are debugged from the same region the agent runs in.
Build on infrastructure that can see its own tail
Ankr runs its own nodes and the gateway in front of them. Every request we serve can be traced to the node that answered, and the block height that node held, which is how we found the incidents in this article and why we can describe our failure modes instead of pointing to a clean success rate.
Agent RPC puts that infrastructure behind one connection. The raw-RPC tools reach any read method on any chain Ankr serves, so explicit-height reads work wherever your agent needs them. Indexed reads cover 29 networks. With TORPC, block numbers and timestamps arrive as decimal strings instead of hex, which removes a conversion step the model could get wrong. The tier is negotiated per call and falls back to tier 0, raw hex, so the freshness check should still be able to parse hex values.
Try it now
Both planes are live. You'll need an API key from Ankr.
Data plane at mcp.ankr.com/rpc, authenticated with your key in the x-ankr-api-key header. Tier 2 is verified on 22 EVM networks today, and the raw-RPC tools reach any chain Ankr serves.
Management plane at mcp.ankr.com/mcp, browser sign-in once through OAuth, after which your agent can run the account paying for those reads.
Connecting takes about two minutes in Claude Code or Cursor. Pin your first height, check your first timestamp, and your agent will know when the chain it's reading is the chain that exists.





