{"record":{"id":"80416d921d5f1d3e","repo":"nautechsystems/nautilus_trader","slug":"failed-to-parse-eth-call-response-e-raw-respons","errorCode":null,"errorMessage":"Failed to parse eth call response: {e}\nRaw response: {preview}","messagePattern":"Failed to parse eth call response: (.+?)\nRaw response: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/rpc/http.rs","lineNumber":165,"sourceCode":"    /// the response into the specified type T.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the HTTP RPC request fails or the response cannot be parsed.\n    pub async fn execute_rpc_call_with_timeout<T: DeserializeOwned>(\n        &self,\n        rpc_request: serde_json::Value,\n        timeout_secs: Option<u64>,\n    ) -> anyhow::Result<T> {\n        let bytes = self\n            .send_rpc_request(rpc_request, timeout_secs)\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to execute eth call RPC request: {e}\"))?;\n        let parsed =\n            serde_json::from_slice::<RpcNodeHttpResponse<T>>(bytes.as_ref()).map_err(|e| {\n                let raw_response = String::from_utf8_lossy(bytes.as_ref());\n                let preview = rpc_response_preview(&raw_response);\n                anyhow::anyhow!(\"Failed to parse eth call response: {e}\\nRaw response: {preview}\")\n            })?;\n\n        // Check for non-standard rate limit error (e.g., Infura)\n        // These responses have code/message at top level without jsonrpc field\n        if parsed.jsonrpc.is_none()\n            && let (Some(code), Some(message)) = (parsed.code, parsed.message)\n        {\n            anyhow::bail!(\"RPC provider error {code}: {message}\");\n        }\n\n        if let Some(error) = parsed.error {\n            anyhow::bail!(\"RPC error {}: {}\", error.code, error.message);\n        }\n\n        parsed\n            .result\n            .ok_or_else(|| anyhow::anyhow!(\"Response missing both result and error fields\"))\n    }","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/rpc/http.rs#L147-L183","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Inspect the 'Raw response' preview in the error message — it reveals whether the body is HTML, empty, or truncated JSON.","Confirm the configured URL is the JSON-RPC endpoint of the node (not a dashboard or REST API path).","Check provider rate limits / plan quotas if the preview shows a rate-limit or upgrade notice.","Ensure no proxy or middleware is rewriting the response; test the same eth_call with curl."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// probe that the URL returns JSON-RPC shaped content before using it\nlet body: serde_json::Value = probe_post(rpc_url, eth_chain_id_request()).await?;\nif body.get(\"jsonrpc\").is_none() && body.get(\"result\").is_none() && body.get(\"error\").is_none() {\n    return Err(\"endpoint does not speak JSON-RPC\".into());\n}","typeGuard":null,"tryCatchPattern":"match execute_rpc_call(&client, req).await {\n    Ok(v) => Ok(v),\n    Err(e) if e.to_string().contains(\"Failed to parse eth call response\") => {\n        // extract the raw preview, inspect for HTML/rate-limit text, then failover\n        switch_to_backup_provider().await\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Always read the 'Raw response' preview in the error before guessing the cause.","Point the client at the JSON-RPC endpoint, not a dashboard/REST path.","Watch for HTML in responses — a sign of rate limiting or proxy interception.","Test the endpoint with curl using the same eth_call payload."],"tags":["rpc","json","parsing","http"],"backgroundTag":"invalid-json-response","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}