linera-io/linera-protocol · error · EthereumQueryError
the ID should be matching
Error message
the ID should be matching
What it means
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).
Source
Thrown at linera-ethereum/src/client.rs:47
async fn request_inner(&self, payload: Vec<u8>) -> Result<Vec<u8>, Self::Error>;
/// Gets a new ID for the next message.
async fn get_id(&self) -> u64;
/// The function doing the parsing of the input and output.
async fn request<T, R>(&self, method: &str, params: T) -> Result<R, Self::Error>
where
T: Debug + Serialize + Send + Sync,
R: DeserializeOwned + Send,
{
let id = self.get_id().await;
let payload = JsonRpcRequest::new(id, method, params);
let payload = serde_json::to_vec(&payload)?;
let body = self.request_inner(payload).await?;
let result = serde_json::from_slice::<JsonRpcResponse>(&body)?;
let raw = result.result;
let res = serde_json::from_str(raw.get())?;
ensure!(id == result.id, EthereumQueryError::IdIsNotMatching);
ensure!(
"2.0" == result.jsonrpc,
EthereumQueryError::WrongJsonRpcVersion
);
Ok(res)
}
}
#[derive(Serialize, Deserialize, Debug)]
struct JsonRpcRequest<'a, T> {
id: u64,
jsonrpc: &'a str,
method: &'a str,
params: T,
}
impl<'a, T> JsonRpcRequest<'a, T> {
/// Creates a new JSON RPC request, the id does not matterView on GitHub (pinned to 6c226ddcb3)
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
Example fix
// before
let client = EthereumClient::new("https://my-gateway.example/rpc"); // gateway rewrites ids
// after
let client = EthereumClient::new("http://eth-node.internal:8545"); // direct JSON-RPC 2.0 node Defensive patterns
Strategy: validation
Validate before calling
// Smoke-test an endpoint before wiring it into the client: the response id must echo the request.
async fn endpoint_correlates_ids(url: &str) -> bool {
let body = r#"{"jsonrpc":"2.0","id":424242,"method":"eth_blockNumber","params":[]}"#;
let resp: serde_json::Value = reqwest::Client::new()
.post(url)
.header("content-type", "application/json")
.body(body)
.send().await.unwrap()
.json().await.unwrap();
resp.get("id") == Some(&serde_json::json!(424242))
} Type guard
fn is_id_mismatch(err: &EthereumQueryError) -> bool {
matches!(err, EthereumQueryError::IdIsNotMatching)
} Try / catch
match client.get_balance(address).await {
Err(e) if is_id_mismatch(&e) => {
// The endpoint mangles request ids; switch to a direct node URL or another provider.
Err(EthereumServiceError::EthereumQueryError(e))
}
other => other,
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- wrong JSON-RPC version
- expected exactly 2 topics (signature + indexed depositor), g
- expected 224 bytes of event data (7 x 32), got {}
- invalid ABI encoding: depositor topic padding bytes (0..12)
- invalid ABI encoding: address padding bytes (128..140) must
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/7b5dd4bb8ada4f17.
Report an issue: GitHub.