nautechsystems/nautilus_trader · error · anyhow::Error

Failed to persist broadcast attempt for transaction {tx_hash

Error message

Failed to persist broadcast attempt for transaction {tx_hash}: {e}; the in-flight slot stays occupied

What it means

Immediately before broadcasting, the client records the 'Broadcast' status attempt via record_execution_status and that Postgres write failed ({e} carries the DB error). Because the write precedes send_raw_transaction, the transaction was not broadcast this attempt; the in-flight slot stays occupied so the intent cannot be double-processed, and reconciliation on the next connect completes the recovery.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:1570

    /// Broadcasts the signed transaction and classifies the acceptance outcome.
    async fn broadcast(&self, prepared: &PreparedTransaction) -> anyhow::Result<BroadcastOutcome> {
        let tx_hash = prepared.tx_hash;

        self.database
            .record_execution_status(
                prepared.intent_id,
                &tx_hash.to_string(),
                TransactionStatus::Broadcast,
                None,
                None,
                None,
                None,
                None,
            )
            .await
            .map_err(|e| {
                anyhow::anyhow!(
                    "Failed to persist broadcast attempt for transaction {tx_hash}: {e}; the in-flight slot stays occupied"
                )
            })?;

        match self
            .http_rpc_client
            .send_raw_transaction(&prepared.raw_tx, &tx_hash)
            .await
        {
            Ok(broadcast_hash) => {
                if broadcast_hash != tx_hash {
                    // The node acknowledged a different hash: acceptance of the signed
                    // transaction is unverified, so reconcile through the persisted record
                    // rather than poll a hash that cannot match the chain
                    return Ok(BroadcastOutcome::Ambiguous(format!(
                        "Broadcast of transaction {tx_hash} returned a differing hash {broadcast_hash}; the persisted record reconciles instead of rebroadcasting"
                    )));
                }

View on GitHub (pinned to 2114cf6f76)

Solutions

  1. Reconnect the client after restoring database service: reconciliation loads the active intent, sees the signed hash, and safely re-drives broadcast/finality
  2. Verify the intent row: SELECT status FROM execution_intent WHERE id = <intent_id>; it should still be 'signed', which reconciliation handles explicitly
  3. Keep the same wallet and Postgres store configured so reconciliation finds the intent
  4. Fix the underlying DB reliability issue (pool sizing, timeouts, HA) surfaced by {e}
Defensive patterns

Strategy: try-catch

Validate before calling

-- Pre-trade DB liveness check (cheap canary the caller can run)
SELECT 1 AS ok;
-- Any timeout here means the broadcast-attempt persist will likely fail too; pause trading.

Try / catch

try:
    await submit_and_wait(order)
except Exception as e:
    if 'Failed to persist broadcast attempt' in str(e):
        # tx was NOT broadcast this attempt; slot stays occupied on purpose.
        # Restore DB, reconnect with the same wallet/store, and let reconciliation re-drive broadcast.
        alert_ops('broadcast persist failure - reconnect to reconcile')
        raise

Prevention

When it happens

Trigger: broadcast() hitting a DB error (connection loss, constraint failure, timeout) at the record_execution_status(TransactionStatus::Broadcast) call, before any RPC send is attempted.

Common situations: Transient Postgres outages at the worst moment; schema drift in the status-history table after a partial migration; connection pool exhaustion under concurrent strategy load.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21). Data as JSON: /api/errors/25406f5b726a20e7. Report an issue: GitHub.