nautechsystems/nautilus_trader · error · anyhow::Error

Transaction broadcast failed: code={}, log={}

Error message

Transaction broadcast failed: code={}, log={}

What it means

`broadcast_tx` submits a transaction to the dYdX chain in sync broadcast mode; if the node's tx_response reports a non-zero code, the TX was rejected and the method bails with the chain's code and raw log. This surfaces on-chain rejection reasons (insufficient fees, sequence mismatch, invalid order, etc.).

Source

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

            .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 {
                anyhow::bail!(
                    "Transaction broadcast failed: code={}, log={}",
                    tx_response.code,
                    tx_response.raw_log
                );
            }
            Ok(tx_response.txhash)
        } else {
            Err(anyhow::anyhow!(
                "Broadcast response does not contain tx_response"
            ))
        }
    }

    /// Query transaction by hash.
    ///
    /// # Errors
    ///
    /// Returns an error if the query fails.

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read `code` and `raw_log` in the message — the raw log names the exact chain rejection reason
  2. Refresh the account sequence/number before re-broadcasting
  3. Increase gas limit or set gas price to meet the network minimum
  4. Re-check order parameters against dYdX chain validation rules
  5. Verify node status / chain is not halted for an upgrade

Example fix

// before: blind retry
client.broadcast_tx(tx).await?;
// after: inspect code/log and resync sequence
match client.broadcast_tx(tx.clone()).await {
    Err(e) if e.to_string().contains("code=32") => { // sequence mismatch
        tx_manager.resync_sequence().await?;
        client.broadcast_tx(tx).await?;
    }
    r => r?,
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure sequence is fresh and gas is sufficient before broadcast
tx_manager.refresh_account().await?;
debug_assert!(tx.gas >= estimated_min_gas);

Try / catch

match client.broadcast_tx(tx).await {
    Err(e) => {
        let msg = e.to_string();
        if msg.contains("code=32") { tx_manager.resync_sequence().await?; /* retry */ }
        else if msg.contains("out of gas") || msg.contains("fee") { raise_gas_and_retry(); }
        else { return Err(e); }
    }
    Ok(h) => Ok(h),
}

Prevention

When it happens

Trigger: Any TX broadcast (order submit/cancel) where the chain returns tx_response.code != 0 — e.g. out-of-gas, wrong account sequence, under-minimum gas price, or rejected msg content.

Common situations: Gas price/limit misconfigured relative to network minimums; account sequence desync after a restart; submitting during chain halt or upgrades; malformed order params failing chain validation.

Related errors


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