nautechsystems/nautilus_trader · error · anyhow::Error

Simulation response does not contain gas info

Error message

Simulation response does not contain gas info

What it means

simulate_tx submits a simulated transaction to the tx service and reads gas_used from the optional `gas_info` field; when the node returns a sim response without gas info the library cannot estimate gas and raises this error. This indicates the simulation produced no gas accounting, often because the tx itself failed to execute in simulation.

Source

Thrown at crates/adapters/dydx/src/grpc/client.rs:469

    }

    /// Simulate a transaction to estimate gas usage.
    ///
    /// # Errors
    ///
    /// Returns an error if simulation fails.
    pub async fn simulate_tx(&mut self, tx_bytes: Vec<u8>) -> Result<u64, anyhow::Error> {
        let req = SimulateRequest {
            tx_bytes,
            ..Default::default()
        };
        let gas_used = self
            .tx
            .simulate(req)
            .await?
            .into_inner()
            .gas_info
            .ok_or_else(|| anyhow::anyhow!("Simulation response does not contain gas info"))?
            .gas_used;
        Ok(gas_used)
    }

    /// Broadcast a signed transaction.
    ///
    /// # Errors
    ///
    /// Returns an error if broadcasting fails.
    pub async fn broadcast_tx(&mut self, tx_bytes: Vec<u8>) -> Result<TxHash, anyhow::Error> {
        let req = BroadcastTxRequest {
            tx_bytes,
            mode: BroadcastMode::Sync as i32,
        };
        let response = self.tx.broadcast_tx(req).await?.into_inner();

        if let Some(tx_response) = response.tx_response {
            if tx_response.code != 0 {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the account's on-chain balances/positions; the tx likely fails at execution, removing gas accounting.
  2. Retry the simulation; transient node conditions can drop gas_info.
  3. Use a different RPC node or increase the sim timeout.
  4. Fall back to a conservative hardcoded gas limit instead of the simulated value.

Example fix

// before
let gas = client.simulate_tx(&tx_bytes).await?;
// after: fallback gas limit on missing gas info
let gas = match client.simulate_tx(&tx_bytes).await {
    Ok(g) => g,
    Err(_) if fallback_allowed => DEFAULT_SIM_GAS_LIMIT,
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: fallback

Validate before calling

// ensure subaccount has sufficient collateral before simulating
let sub = client.get_subaccount(owner, 0).await?;
anyhow::ensure!(has_enough_equity(&sub, order), "insufficient equity for order");

Try / catch

let gas_used = match client.simulate_tx(&tx_bytes).await {
    Ok(g) if g > 0 => g,
    Ok(_) | Err(_) => DEFAULT_SIM_GAS_LIMIT, // conservative fallback
};

Prevention

When it happens

Trigger: Calling simulate_tx with a transaction that reverts during simulation (e.g. insufficient balance, invalid order) so the node returns no gas_info, or against a node that doesn't populate gas_info.

Common situations: Simulating a market order when the subaccount lacks collateral; node misconfiguration or older node version omitting gas_info; network congestion causing sim aborts.

Related errors


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