nautechsystems/nautilus_trader · error

{method} RPC error {}

Error message

{method} RPC error {}

What it means

A typed execution RPC call (`chain_id`, `get_storage_at`, `get_code_with_block`, `get_transaction_count_*`) received a standard JSON-RPC error object from the node. The message includes the method name and the JSON-RPC error code but discards the node's `message` detail, so consult the code (-32601 unsupported method, -32602 invalid params, -32000/-32005 server/limit errors). The node received and rejected the request at protocol level.

Source

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

                BlockchainRpcClientError::ClientError(message)
                    if message.contains("redirect response rejected") =>
                {
                    anyhow::anyhow!("{method} redirect rejected")
                }
                _ => anyhow::anyhow!("{method} request failed"),
            })?;

        let parsed = serde_json::from_slice::<RpcNodeHttpResponse<T>>(bytes.as_ref())
            .map_err(|_| anyhow::anyhow!("Failed to parse {method} response"))?;

        if parsed.jsonrpc.is_none()
            && let (Some(code), Some(_message)) = (parsed.code, parsed.message)
        {
            anyhow::bail!("{method} RPC error {code}");
        }

        if let Some(error) = parsed.error {
            anyhow::bail!("{method} RPC error {}", error.code);
        }

        Ok(parsed.result)
    }

    /// Returns the chain ID reported by the RPC node via `eth_chainId`.
    ///
    /// # Errors
    ///
    /// Returns an error if the RPC call fails or the result is missing or malformed.
    pub async fn chain_id(&self) -> anyhow::Result<u64> {
        let result: Option<String> = self
            .execute_execution_rpc_call("eth_chainId", serde_json::json!([]))
            .await?;
        parse_hex_quantity_result("eth_chainId", result)
            .and_then(|v| u64::try_from(v).map_err(Into::into))
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Decode the error code: fix params for -32602, switch endpoints for -32601, back off for -32005
  2. Validate all hex params (address length, 32-byte storage slot with 0x prefix) before the call
  3. For historical block queries, use an archive node instead of a pruned full node
  4. Retry only transient codes with backoff; add a fallback RPC endpoint for hard failures

Example fix

// before: unvalidated storage slot
let slot = format!("{}", index); // decimal, not 0x-hex32
let v = rpc.get_storage_at(contract, slot, block).await?;
// after
let slot = format!("0x{:064x}", index);
let v = rpc.get_storage_at(contract, slot, block).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn valid_slot(slot: &str) -> bool { slot.starts_with("0x") && slot.len() <= 66 && slot[2..].chars().all(|c| c.is_ascii_hexdigit()) }
// format slots as 0x{:064x}, addresses as 0x + 40 hex chars

Try / catch

match typed_call().await {
    Err(e) if e.to_string().contains("RPC error -32602") => fix_params_and_retry(),
    Err(e) if e.to_string().contains("RPC error -32601") => use_alternate_endpoint(),
    Err(e) => Err(e),
    Ok(v) => Ok(v),
}

Prevention

When it happens

Trigger: `execute_execution_rpc_call` gets a response with a populated `error` field for any of the wrapper methods: e.g. `eth_getStorageAt` with a malformed slot hex, `eth_getCode` at an unsupported block tag on a pruned node, or `eth_chainId` on an endpoint that doesn't expose it.

Common situations: Pruned/light nodes rejecting historical block queries; invalid storage-slot or address hex in params; endpoints that don't support certain methods (some L2/gateway RPCs); node returning -32005 limit exceeded under load.

Related errors


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