nautechsystems/nautilus_trader · error · anyhow::Error

WETH balance overflow for included transaction {tx_hash} at

Error message

WETH balance overflow for included transaction {tx_hash} at block {block_number}: wrap amount {amount_wei} from balance {balance_before}

What it means

In ensure_wrap_balance_increase (crates/adapters/blockchain/src/execution/client.rs:701) the expected post-wrap balance is computed as balance_before.checked_add(amount_wei); on U256 overflow the check aborts instead of wrapping around. Because 2^256 wei exceeds any real token supply by dozens of orders of magnitude, an overflow can only occur when the RPC returns a corrupted balanceOfAt historical read (balance_before near U256::MAX) or an absurd amount. It is an arithmetic-integrity guard against bad node data, not a realistic accounting event.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:701

            .erc20_contract
            .balance_of_at(weth_address, &self.wallet_address, previous_block)
            .await
            .with_context(|| {
                format!(
                    "failed to read WETH balance before included transaction {tx_hash} at block {previous_block}"
                )
            })?;
        let balance_after = self
            .erc20_contract
            .balance_of_at(weth_address, &self.wallet_address, block_number)
            .await
            .with_context(|| {
                format!(
                    "failed to read WETH balance after included transaction {tx_hash} at block {block_number}"
                )
            })?;
        let expected_balance = balance_before.checked_add(amount_wei).ok_or_else(|| {
            anyhow::anyhow!(
                "WETH balance overflow for included transaction {tx_hash} at block {block_number}: wrap amount {amount_wei} from balance {balance_before}"
            )
        })?;

        if balance_after != expected_balance {
            anyhow::bail!(
                "WETH balance after transaction {tx_hash} did not increase by {amount_wei}: expected {expected_balance}, was {balance_after}"
            );
        }

        Ok(())
    }

    /// Ensures the router allowance at the block that included transaction `tx_hash` covers
    /// `amount`. Shared by the live approve path and restart reconciliation.
    async fn ensure_approve_allowance(
        &self,
        token: &Address,

View on GitHub (pinned to d1527c24af)

Solutions

  1. Query the wallet's WETH balance at the named blocks directly (explorer or second RPC) and compare with what the node returned.
  2. Switch to a reliable, synced RPC provider and retry the operation.
  3. If triggered during restart reconciliation, clear the affected intent only after confirming the on-chain final state.
  4. Report recurring garbage reads to the node operator; this error protects against silently accepting fabricated balances.
Defensive patterns

Strategy: try-catch

Type guard

fn is_wrap_balance_overflow(e: &anyhow::Error) -> bool {
    e.to_string().contains("WETH balance overflow")
}

Try / catch

match client.wrap(amount_wei).await {
    Ok(tx_hash) => tx_hash,
    Err(e) if is_wrap_balance_overflow(&e) => {
        // node returned a corrupted historical balance; halt and audit the RPC source
        log::error!("suspicious balanceOfAt data from RPC: {e}");
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A misbehaving or malicious RPC returning garbage for the historical WETH balanceOfAt at block-1; a replayed or tampered RPC response feeding near-max U256 values; wrap amount corrupted in memory or in the persisted intent being reconciled.

Common situations: Flaky free RPC endpoints; a node serving inconsistent state during reorgs; extremely rare and almost always a symptom of a broken data source rather than user error.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@d1527c24af (2026-08-21). Data as JSON: /api/errors/f1983ab9f1455ff3. Report an issue: GitHub.