nautechsystems/nautilus_trader · error

eth_call execution reverted

Error message

eth_call execution reverted

What it means

Raised by `call_at` in the blockchain HTTP RPC adapter when an explicit-height `eth_call` is recognized as having reverted on-chain. The underlying `call_result_at` preserves the revert as data via `RpcCallResult::Reverted`, but the plain `call_at` API discards the revert data and converts it into this anyhow error. It means the contract executed the calldata and deliberately reverted (e.g. require/assert failed), not that the RPC itself failed.

Source

Thrown at crates/adapters/blockchain/src/rpc/http.rs:504

    /// # Errors
    ///
    /// Returns an error if the RPC call fails or the result is missing or malformed.
    #[cfg(feature = "hypersync")]
    #[allow(
        dead_code,
        reason = "Used by the independent verification read inventory"
    )]
    pub(crate) async fn call_at(
        &self,
        from: Option<&Address>,
        to: &Address,
        value: U256,
        data: &[u8],
        block: u64,
    ) -> anyhow::Result<Bytes> {
        match self.call_result_at(from, to, value, data, block).await? {
            RpcCallResult::Success(bytes) => Ok(bytes),
            RpcCallResult::Reverted => anyhow::bail!("eth_call execution reverted"),
        }
    }

    /// Executes an explicit-height `eth_call`, preserving a recognized EVM revert as data.
    #[cfg(feature = "hypersync")]
    pub(crate) async fn call_result_at(
        &self,
        from: Option<&Address>,
        to: &Address,
        value: U256,
        data: &[u8],
        block: u64,
    ) -> anyhow::Result<RpcCallResult> {
        let mut call = serde_json::json!({
            "to": to,
            "value": format!("0x{value:x}"),
            "data": hex::encode_prefixed(data),
        });

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Decode the revert reason instead: use `call_result_at` which returns `RpcCallResult::Reverted` and preserves the revert data.
  2. Check preconditions on-chain before the call (allowance, balance, role, state at `block`).
  3. Verify the calldata encoding (function selector and ABI arguments) — malformed calldata often reverts.
  4. Confirm the target contract is deployed at the queried `block` height.

Example fix

// before
let out = rpc.call_at(from, to, value, data, block).await?;
// after
match rpc.call_result_at(from, to, value, data, block).await? {
    RpcCallResult::Success(bytes) => bytes,
    RpcCallResult::Reverted => decode_revert_reason(data) /* handle revert */, 
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Check state preconditions before the call
let allowance: U256 = erc20.allowance(owner, spender).call().await?;
anyhow::ensure!(allowance >= amount, "insufficient allowance, eth_call would revert");

Type guard

fn is_reverted(err: &anyhow::Error) -> bool {
    err.to_string().contains("eth_call execution reverted")
}

Try / catch

match rpc.call_at(from, to, value, data, block).await {
    Ok(bytes) => process(bytes),
    Err(e) if is_reverted(&e) => handle_revert(decode_revert_data(&e)),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `call_at(from, to, value, data, block)` where the contract at `to` reverts when executed at the given historical block: failed `require`/`assert`, custom error, or explicit `revert()` in the contract logic.

Common situations: Simulating a token transfer that would fail (insufficient allowance/balance); calling a view function guarded by state checks that don't hold at the queried block; probing historical state where the contract wasn't deployed or a check like `onlyOwner` fails.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/250ae0abea822b72. Report an issue: GitHub.