nautechsystems/nautilus_trader · error

Failed to decode eth_call response

Error message

Failed to decode eth_call response

What it means

Raised in `call_result_at` when the `result` string of a successful `eth_call` response is not valid hex (after stripping the `0x` prefix). The library expects the node to return a `0x`-prefixed hex-encoded ABI byte string and fails fast when the value cannot be hex-decoded into `Bytes`.

Source

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

        {
            if eth_call_error_is_revert(code, &message) {
                return Ok(RpcCallResult::Reverted);
            }
            anyhow::bail!("eth_call RPC error {code}");
        }

        if let Some(error) = parsed.error {
            if eth_call_error_is_revert(error.code, &error.message) {
                return Ok(RpcCallResult::Reverted);
            }
            anyhow::bail!("eth_call RPC error {}", error.code);
        }
        let value = parsed
            .result
            .ok_or_else(|| anyhow::anyhow!("eth_call returned no result"))?;
        let stripped = value.strip_prefix("0x").unwrap_or(&value);
        let bytes = hex::decode(stripped)
            .map_err(|_| anyhow::anyhow!("Failed to decode eth_call response"))?;
        Ok(RpcCallResult::Success(Bytes::from(bytes)))
    }

    /// Estimates the gas required for a transaction via `eth_estimateGas`.
    ///
    /// # Errors
    ///
    /// Returns an error if the RPC call fails (including node-side revert of the simulated
    /// transaction) or the result is missing or malformed.
    pub async fn estimate_gas(
        &self,
        from: &Address,
        to: &Address,
        value: U256,
        data: &[u8],
    ) -> anyhow::Result<u64> {
        self.estimate_gas_with_block(from, to, value, data, None)
            .await

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Print/log the raw `result` string from the failing call to see what the node actually returned
  2. Validate the node returns spec-compliant `0x`-prefixed hex (test with a simple eth_call against eth_chainId-style data)
  3. Switch to a standards-compliant execution client (geth/reth/erigon) or mainstream provider
  4. If odd-length hex comes from your own ABI encoding, fix the encoder before sending the request
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate node hex compliance with a known call
let v: serde_json::Value = send_raw(rpc_url, json!({"jsonrpc":"2.0","method":"eth_chainId","id":1})).await?;
let hex_ok = v["result"].as_str().map(|s| s.starts_with("0x") && hex::decode(&s[2..]).is_ok()).unwrap_or(false);

Type guard

fn is_hex_bytes(s: &str) -> bool {
    let t = s.strip_prefix("0x").unwrap_or(s);
    !t.is_empty() && t.len() % 2 == 0 && t.chars().all(|c| c.is_ascii_hexdigit())
}

Try / catch

match client.call_at(&tx, block).await {
    Ok(res) => Ok(res),
    Err(e) if e.to_string().contains("Failed to decode eth_call response") => {
        Err(anyhow!("node returned non-hex eth_call result; check client compliance: {e}"))
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: The node returns a `result` that is not hex, e.g. an empty string, a non-hex error text smuggled into `result`, odd-length hex, or a decimal value from a non-conforming node.

Common situations: Custom or older execution clients that return unprefixed or odd-length hex; a node returning error text in `result` after an upstream proxy mangled the response; contract ABI output truncated by response size limits.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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