nautechsystems/nautilus_trader · error

Failed to parse eth call response: {e} Raw response: {previe

Error message

Failed to parse eth call response: {e}
Raw response: {preview}

What it means

After a successful transport, execute_rpc_call_with_timeout deserializes the bytes into RpcNodeHttpResponse<T>. If the body is not a well-formed JSON-RPC response object, it fails with this error and includes a truncated raw response preview for debugging. This means the node returned HTTP 200 but with unexpected content.

Source

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

    /// the response into the specified type T.
    ///
    /// # Errors
    ///
    /// Returns an error if the HTTP RPC request fails or the response cannot be parsed.
    pub async fn execute_rpc_call_with_timeout<T: DeserializeOwned>(
        &self,
        rpc_request: serde_json::Value,
        timeout_secs: Option<u64>,
    ) -> anyhow::Result<T> {
        let bytes = self
            .send_rpc_request(rpc_request, timeout_secs)
            .await
            .map_err(|e| anyhow::anyhow!("Failed to execute eth call RPC request: {e}"))?;
        let parsed =
            serde_json::from_slice::<RpcNodeHttpResponse<T>>(bytes.as_ref()).map_err(|e| {
                let raw_response = String::from_utf8_lossy(bytes.as_ref());
                let preview = rpc_response_preview(&raw_response);
                anyhow::anyhow!("Failed to parse eth call response: {e}\nRaw response: {preview}")
            })?;

        // Check for non-standard rate limit error (e.g., Infura)
        // These responses have code/message at top level without jsonrpc field
        if parsed.jsonrpc.is_none()
            && let (Some(code), Some(message)) = (parsed.code, parsed.message)
        {
            anyhow::bail!("RPC provider error {code}: {message}");
        }

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

        parsed
            .result
            .ok_or_else(|| anyhow::anyhow!("Response missing both result and error fields"))
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the 'Raw response' preview in the error message — it reveals whether the body is HTML, empty, or truncated JSON.
  2. Confirm the configured URL is the JSON-RPC endpoint of the node (not a dashboard or REST API path).
  3. Check provider rate limits / plan quotas if the preview shows a rate-limit or upgrade notice.
  4. Ensure no proxy or middleware is rewriting the response; test the same eth_call with curl.
Defensive patterns

Strategy: try-catch

Validate before calling

// probe that the URL returns JSON-RPC shaped content before using it
let body: serde_json::Value = probe_post(rpc_url, eth_chain_id_request()).await?;
if body.get("jsonrpc").is_none() && body.get("result").is_none() && body.get("error").is_none() {
    return Err("endpoint does not speak JSON-RPC".into());
}

Try / catch

match execute_rpc_call(&client, req).await {
    Ok(v) => Ok(v),
    Err(e) if e.to_string().contains("Failed to parse eth call response") => {
        // extract the raw preview, inspect for HTML/rate-limit text, then failover
        switch_to_backup_provider().await
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Calling execute_rpc_call or get_balance_with_timeout when the RPC endpoint returns a non-JSON or malformed body — provider error pages, HTML rate-limit notices, empty bodies, or proxies intercepting the request.

Common situations: Rate limiting from providers like Infura/Alchemy returning HTML or plain-text errors with 200; corporate proxies or captive portals injecting content; pointing the client at a non-JSON-RPC URL (e.g. a REST endpoint or web page).

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


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