nautechsystems/nautilus_trader · error

Response missing both result and error fields

Error message

Response missing both result and error fields

What it means

execute_rpc_call_with_timeout expects every JSON-RPC response to carry either a result or an error field. If RpcNodeHttpResponse has neither, the node returned a structurally valid but semantically empty response, and the code fails with this error rather than returning None. This indicates a non-conforming or buggy RPC endpoint.

Source

Thrown at crates/adapters/blockchain/src/rpc/http.rs:182

                let preview = rpc_response_preview(&raw_response);
                anyhow::anyhow!("Failed to parse eth call response: {e}\nRaw response: {preview}")
            })?;

        // Check for non-standard rate limit error (e.g., Infura)
        // These responses have code/message at top level without jsonrpc field
        if parsed.jsonrpc.is_none()
            && let (Some(code), Some(message)) = (parsed.code, parsed.message)
        {
            anyhow::bail!("RPC provider error {code}: {message}");
        }

        if let Some(error) = parsed.error {
            anyhow::bail!("RPC error {}: {}", error.code, error.message);
        }

        parsed
            .result
            .ok_or_else(|| anyhow::anyhow!("Response missing both result and error fields"))
    }

    /// Creates a properly formatted `eth_call` JSON-RPC request object targeting a specific contract address with encoded function data.
    #[must_use]
    pub fn construct_eth_call(
        &self,
        to: &str,
        call_data: &[u8],
        block: Option<u64>,
    ) -> serde_json::Value {
        self.construct_eth_call_request(None, to, call_data, block)
    }

    fn construct_eth_call_request(
        &self,
        from: Option<&Address>,
        to: &str,
        call_data: &[u8],

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Log the raw response body for this case to see what the node actually returned.
  2. Point the client directly at a standard JSON-RPC node, bypassing any gateway/proxy layer.
  3. If the provider legitimately returns this shape, pre-validate with a simple request (eth_chainId) and switch providers if non-conformant.
  4. Update to a newer version of the client, which may handle additional non-standard response shapes.
Defensive patterns

Strategy: try-catch

Validate before calling

// health-check the provider conforms to JSON-RPC at startup
let v: serde_json::Value = post_json(rpc_url, eth_chain_id_request()).await?;
if v.get("result").is_none() && v.get("error").is_none() {
    return Err("provider returns non-conformant JSON-RPC responses".into());
}

Try / catch

match execute_rpc_call(&client, req).await {
    Ok(v) => Ok(v),
    Err(e) if e.to_string().contains("Response missing both result and error fields") => {
        // non-conformant endpoint: log raw body and failover
        tracing::error!("non-conformant RPC response; switching provider");
        switch_to_backup_provider().await
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Calling execute_rpc_call or get_balance_with_timeout against a node that returns a JSON object without both 'result' and 'error' — e.g. a partially standard-compliant proxy, a load balancer health response, or a non-standard rate-limit body that also lacked top-level code/message.

Common situations: Routing through API gateways that intercept and return custom JSON envelopes; misconfigured reverse proxies in front of the node; provider returning unusual shaped errors that evade both the error branch and the Infura-style rate-limit check.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/aa131d40b65490f6. Report an issue: GitHub.