{"record":{"id":"19410fecc572ed18","repo":"nautechsystems/nautilus_trader","slug":"failed-to-parse-eth-call-response","errorCode":null,"errorMessage":"Failed to parse eth_call response","messagePattern":"Failed to parse eth_call response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/rpc/http.rs","lineNumber":545,"sourceCode":"        let request = serde_json::json!({\n            \"jsonrpc\": \"2.0\",\n            \"id\": 1,\n            \"method\": \"eth_call\",\n            \"params\": [call, block_parameter(Some(block))],\n        });\n        let bytes = self\n            .send_rpc_request(request, Some(EXECUTION_RPC_TIMEOUT_SECS))\n            .await\n            .map_err(|e| match e {\n                BlockchainRpcClientError::ClientError(message)\n                    if message.contains(\"redirect response rejected\") =>\n                {\n                    anyhow::anyhow!(\"eth_call redirect rejected\")\n                }\n                _ => anyhow::anyhow!(\"eth_call request failed\"),\n            })?;\n        let parsed = serde_json::from_slice::<RpcNodeHttpResponse<String>>(bytes.as_ref())\n            .map_err(|_| anyhow::anyhow!(\"Failed to parse eth_call response\"))?;\n\n        if parsed.jsonrpc.is_none()\n            && let (Some(code), Some(message)) = (parsed.code, parsed.message)\n        {\n            if eth_call_error_is_revert(code, &message) {\n                return Ok(RpcCallResult::Reverted);\n            }\n            anyhow::bail!(\"eth_call RPC error {code}\");\n        }\n\n        if let Some(error) = parsed.error {\n            if eth_call_error_is_revert(error.code, &error.message) {\n                return Ok(RpcCallResult::Reverted);\n            }\n            anyhow::bail!(\"eth_call RPC error {}\", error.code);\n        }\n        let value = parsed\n            .result","sourceCodeStart":527,"sourceCodeEnd":563,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/rpc/http.rs#L527-L563","documentation":"This error is raised in `call_result_at` when the HTTP body returned by the node for an `eth_call` cannot be deserialized into the expected `RpcNodeHttpResponse<String>` JSON-RPC envelope. The library expects either a JSON-RPC 2.0 response (with `jsonrpc`/`result`) or a non-standard `{code, message}` error object; anything else (HTML, empty body, truncated JSON, proxy error pages) triggers it. It wraps the raw transport layer so callers get a single anyhow error for the eth_call path.","triggerScenarios":"The `eth_call` HTTP response body is not valid JSON, or is valid JSON that does not match the `RpcNodeHttpResponse<String>` shape (missing both `jsonrpc` and `result`/`code`/`message` fields), e.g. an HTML error page from a reverse proxy, a rate-limit text body, or a non-standard node response.","commonSituations":"Pointing the execution RPC URL at a load balancer or Cloudflare endpoint that returns HTML 502/429 pages; node returning chunked/truncated responses under load; misconfigured port hitting a web UI instead of the JSON-RPC endpoint.","solutions":["Verify the execution RPC URL points at a JSON-RPC endpoint (curl -X POST with an eth_chainId request) and not a dashboard or proxy page","Inspect the raw response body (curl the same eth_call) to see whether the node returns HTML or malformed JSON","Retry against a healthy node or another provider; persistent failures indicate node/proxy issues","Upgrade the adapter/node if the node uses a non-standard JSON-RPC response shape"],"exampleFix":"// before: endpoint returns HTML on error, causing parse failure\nrpc_url = \"https://my-lb.example.com/eth\"  // LB returns HTML 502\n// after: point directly at a JSON-RPC endpoint and pre-check health\nrpc_url = \"https://node.example.com:8545\"\n// curl -X POST $rpc_url -d '{\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"id\":1}'","handlingStrategy":"try-catch","validationCode":"async fn rpc_endpoint_ok(url: &str) -> bool {\n    let body = reqwest::Client::new().post(url)\n        .json(&serde_json::json!({\"jsonrpc\":\"2.0\",\"method\":\"eth_chainId\",\"params\":[],\"id\":1}))\n        .send().await.ok()?.text().await.ok()?;\n    body.trim_start().starts_with('{') && serde_json::from_str::<serde_json::Value>(&body).is_ok()\n}","typeGuard":"fn is_json_rpc_envelope(v: &serde_json::Value) -> bool {\n    v.is_object() && (v.get(\"jsonrpc\").is_some() || v.get(\"result\").is_some() || v.get(\"error\").is_some())\n}","tryCatchPattern":"match client.call_at(&tx, block).await {\n    Ok(res) => handle(res),\n    Err(e) if e.to_string().contains(\"Failed to parse eth_call response\") => {\n        log::warn!(\"non-JSON RPC body; failing over\");\n        fallback_client.call_at(&tx, block).await\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Point the RPC URL directly at a JSON-RPC endpoint, never at a web UI or HTML-serving proxy","Health-check the endpoint with an eth_chainId POST before starting workloads","Disable intermediaries that replace JSON error bodies with HTML (Cloudflare challenge pages, LB error pages)","Pin and monitor node/provider versions to avoid non-standard response shapes"],"tags":["rpc","eth-call","json","parsing"],"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"}