linera-io/linera-protocol · error · EthereumQueryError

wrong JSON-RPC version

Error message

wrong JSON-RPC version

What it means

Raised by linera-ethereum's JsonRpcClient::request when the deserialized response's jsonrpc field is not exactly "2.0". The client only speaks JSON-RPC 2.0 and verifies the version marker on every reply; a different value means the endpoint is not a conforming Ethereum JSON-RPC 2.0 server (e.g. a 1.0-style server or some other HTTP service that happens to return JSON).

Source

Thrown at linera-ethereum/src/client.rs:48

    /// 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 matter
    pub fn new(id: u64, method: &'a str, params: T) -> Self {

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Verify the URL targets the node's JSON-RPC endpoint (default port 8545) and test it: curl -s -X POST -H 'content-type: application/json' --data '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}' <url>
  2. Fix mock servers and gateways to echo "jsonrpc":"2.0" in every response
  3. Replace non-conformant front layers or connect directly to the node

Example fix

// Mock server: return a conforming 2.0 envelope
// before
{"id": 7, "result": "0x1"}
// after
{"jsonrpc": "2.0", "id": 7, "result": "0x1"}
Defensive patterns

Strategy: validation

Validate before calling

async fn speaks_json_rpc_2_0(url: &str) -> bool {
    let body = r#"{"jsonrpc":"2.0","id":1,"method":"web3_clientVersion","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("jsonrpc") == Some(&serde_json::json!("2.0"))
}

Type guard

fn is_wrong_json_rpc_version(err: &EthereumQueryError) -> bool {
    matches!(err, EthereumQueryError::WrongJsonRpcVersion)
}

Try / catch

match client.get_balance(address).await {
    Err(e) if is_wrong_json_rpc_version(&e) => {
        // Endpoint is not JSON-RPC 2.0; fail fast with a clear config error.
        Err(anyhow::anyhow!("configured Ethereum URL is not a JSON-RPC 2.0 endpoint"))
    }
    other => other,
}

Prevention

When it happens

Trigger: URL pointing at a JSON-RPC 1.0 server or an arbitrary JSON HTTP API that includes a jsonrpc field with another value; mock/test doubles not setting the field correctly; gateways that translate between RPC dialects and drop the version.

Common situations: Wrong URL (e.g. an indexer's REST API instead of the node's RPC port); test harnesses with hand-rolled JSON-RPC responders; legacy infrastructure fronting the node.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/c2b6aab977482fe6. Report an issue: GitHub.