{"record":{"id":"7b5dd4bb8ada4f17","repo":"linera-io/linera-protocol","slug":"the-id-should-be-matching","errorCode":null,"errorMessage":"the ID should be matching","messagePattern":"the ID should be matching","errorType":"validation","errorClass":"EthereumQueryError","httpStatus":null,"severity":"error","filePath":"linera-ethereum/src/client.rs","lineNumber":47,"sourceCode":"    async fn request_inner(&self, payload: Vec<u8>) -> Result<Vec<u8>, Self::Error>;\n\n    /// Gets a new ID for the next message.\n    async fn get_id(&self) -> u64;\n\n    /// The function doing the parsing of the input and output.\n    async fn request<T, R>(&self, method: &str, params: T) -> Result<R, Self::Error>\n    where\n        T: Debug + Serialize + Send + Sync,\n        R: DeserializeOwned + Send,\n    {\n        let id = self.get_id().await;\n        let payload = JsonRpcRequest::new(id, method, params);\n        let payload = serde_json::to_vec(&payload)?;\n        let body = self.request_inner(payload).await?;\n        let result = serde_json::from_slice::<JsonRpcResponse>(&body)?;\n        let raw = result.result;\n        let res = serde_json::from_str(raw.get())?;\n        ensure!(id == result.id, EthereumQueryError::IdIsNotMatching);\n        ensure!(\n            \"2.0\" == result.jsonrpc,\n            EthereumQueryError::WrongJsonRpcVersion\n        );\n        Ok(res)\n    }\n}\n\n#[derive(Serialize, Deserialize, Debug)]\nstruct JsonRpcRequest<'a, T> {\n    id: u64,\n    jsonrpc: &'a str,\n    method: &'a str,\n    params: T,\n}\n\nimpl<'a, T> JsonRpcRequest<'a, T> {\n    /// Creates a new JSON RPC request, the id does not matter","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-ethereum/src/client.rs#L29-L65","documentation":"Raised by linera-ethereum's JsonRpcClient::request after deserializing a JSON-RPC response: the id in the response must equal the id the client generated for the request. JSON-RPC 2.0 requires responses to echo the request id so callers can match replies to requests; a mismatch means whatever answered is not correlating responses correctly (proxy rewriting ids, misrouted connection, or a non-conformant server).","triggerScenarios":"Pointing the Ethereum client at an id-mangling middleware: naive load balancers, API gateways, or caching proxies that regenerate or drop the id; a WebSocket multiplexer delivering another request's response; a server that always answers with a fixed id (JSON-RPC 1.0 style). Hit from get_accounts, get_balance, is_block_hash_finalized.","commonSituations":"Using a corporate proxy or custom RPC gateway in front of the Ethereum node instead of the node itself; misconfigured dev/test mock servers; hosted RPC providers with non-standard front layers.","solutions":["Point the client directly at a conforming Ethereum node (reth/geth/besu) endpoint and retest","Remove or fix the middleware in front of the node so it echoes request ids verbatim","If you must use a gateway, verify with curl that a request with id 42 comes back with id 42","Switch to a reputable hosted RPC provider known to be JSON-RPC 2.0 compliant"],"exampleFix":"// before\nlet client = EthereumClient::new(\"https://my-gateway.example/rpc\"); // gateway rewrites ids\n\n// after\nlet client = EthereumClient::new(\"http://eth-node.internal:8545\"); // direct JSON-RPC 2.0 node","handlingStrategy":"validation","validationCode":"// Smoke-test an endpoint before wiring it into the client: the response id must echo the request.\nasync fn endpoint_correlates_ids(url: &str) -> bool {\n    let body = r#\"{\"jsonrpc\":\"2.0\",\"id\":424242,\"method\":\"eth_blockNumber\",\"params\":[]}\"#;\n    let resp: serde_json::Value = reqwest::Client::new()\n        .post(url)\n        .header(\"content-type\", \"application/json\")\n        .body(body)\n        .send().await.unwrap()\n        .json().await.unwrap();\n    resp.get(\"id\") == Some(&serde_json::json!(424242))\n}","typeGuard":"fn is_id_mismatch(err: &EthereumQueryError) -> bool {\n    matches!(err, EthereumQueryError::IdIsNotMatching)\n}","tryCatchPattern":"match client.get_balance(address).await {\n    Err(e) if is_id_mismatch(&e) => {\n        // The endpoint mangles request ids; switch to a direct node URL or another provider.\n        Err(EthereumServiceError::EthereumQueryError(e))\n    }\n    other => other,\n}","preventionTips":["Connect the Ethereum client directly to a node's RPC port; avoid hand-rolled gateways that rewrite ids","Add the id-echo smoke test above to deployment checks for the configured RPC URL","Never share one client connection across concurrent requests through id-ignoring middleware"],"tags":["ethereum","json-rpc","proxy","client","linera-bridge"],"backgroundTag":"json-rpc-response-id-mismatch","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}