← Back to the library
Web3Applied · 7 min

Balances and nonces flip between refreshes

“The same address shows a new balance, then the old one, then the new one again; nonces occasionally go backwards.”

ERROR CODES YOU MAY SEE

A code is a clue. Use its meaning and surrounding evidence to narrow the cause.

NONCE_EXPIREDethers v6 · library

The sending account has already used this nonce in a transaction that has been included.

Check whether an earlier attempt or another signer process already mined this nonce, or whether the nonce came from a lagging RPC node. Look up the mined transaction before resending.

Official reference for NONCE_EXPIRED (opens in new tab)Code definition reviewed

THE PRINCIPLE

latest is a moving, per-node pointer. Consistency comes from naming the block, not from asking the same question again.

FIRST MOVES

  1. Log the block number with every read; flipping values with flipping heights confirms a load-balanced or failover provider.
  2. After a write, read at the receipt's blockNumber or later; retry on unknown-block errors from a node that has not caught up.
  3. For a page of related reads, fetch one block number and pass it to every call so they share one snapshot.
  4. Where reorgs matter, pin by block hash (EIP-1898, requireCanonical: true), or read at safe or finalized.
  5. Keep a high-water mark per client and drop responses from blocks older than one you already showed.
  6. Signers: do not take nonces from an arbitrary pool node; allocate them locally and reconcile.

TOOLS: THEN → NOW

A single latest read per valueBlock-pinned reads (blockNumber, or EIP-1898 blockHash)
Hand-rolled provider switchingFallback transports with ranking and retries, plus height checks

PATTERN SNAPSHOT

const receipt = await client.waitForTransactionReceipt({ hash });
const at = { blockNumber: receipt.blockNumber };

// Both reads see the same state, at least as new as the write.
const [eth, usdc] = await Promise.all([
  client.getBalance({ address: user, ...at }),
  client.readContract({
    address: usdcAddress, abi: erc20Abi,
    functionName: "balanceOf", args: [user], ...at,
  }),
]);

CLOSE THE AI. EXPLAIN THIS.

Why can retrying a latest read make an inconsistency worse rather than better?

HOW IT WORKS UNDERNEATH

SOURCES

Guide reviewed