nautechsystems/nautilus_trader · error · anyhow::Error

Broadcast response does not contain tx_response

Error message

Broadcast response does not contain tx_response

What it means

broadcast_tx checks the broadcast response for the optional `tx_response` field; if absent the node returned no receipt for the submitted transaction and the library raises instead of fabricating a tx hash. This means the broadcast result itself is missing, distinct from a tx that executed and failed (code != 0).

Source

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

    /// 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.
    pub async fn get_tx(&mut self, hash: &str) -> Result<Tx, anyhow::Error> {
        let req = GetTxRequest {
            hash: hash.to_string(),
        };
        let response = self.tx.get_tx(req).await?.into_inner();

        if let Some(tx) = response.tx {
            // Convert through bytes since the types are incompatible

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Retry the broadcast; if using BROADCAST_MODE_ASYNC, consider SYNC to always receive a receipt.
  2. Switch to a healthier RPC endpoint.
  3. After a missing receipt, look up the tx by hash of the signed bytes later, since the tx may still have been committed.
  4. Check node rate limits / authentication requirements on the RPC provider.

Example fix

// before
let hash = client.broadcast_tx(&tx_bytes).await?;
// after: retry once with SYNC mode
let hash = match client.broadcast_tx(&tx_bytes).await {
    Ok(h) => h,
    Err(e) if e.to_string().contains("does not contain tx_response") => {
        client.broadcast_tx_mode(&tx_bytes, BroadcastMode::Sync).await?
    }
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: retry

Try / catch

match client.broadcast_tx(&tx_bytes).await {
    Ok(hash) => Ok(hash),
    Err(e) if e.to_string().contains("does not contain tx_response") => {
        tokio::time::sleep(Duration::from_secs(1)).await;
        client.broadcast_tx(&tx_bytes).await
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Calling broadcast_tx (sync/async mode) when the node accepts the connection but returns a BroadcastTxResponse with tx_response unset — node overload, dropped result, or proto mismatch.

Common situations: Broadcasting during node instability or maintenance; hitting a rate-limited public RPC; using a mode the node doesn't support so no receipt is generated.

Related errors


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