nautechsystems/nautilus_trader · error · anyhow::Error

Failed to commit execution transition: {e}

Error message

Failed to commit execution transition: {e}

What it means

Wrapped sqlx error when transaction.commit() fails at the end of record_execution_status (database.rs:3710-3713). At commit time the work has already executed, so a failure here leaves the outcome ambiguous: the transaction may or may not have durable-committed before the connection died. Because the flow is idempotent (transition_key ON CONFLICT DO NOTHING, COALESCE-guarded hash updates, status re-application is allowed for equal statuses), re-running the same call resolves the ambiguity safely.

Source

Thrown at crates/adapters/blockchain/src/cache/database.rs:3713

            WHERE intent_id = $1 AND transaction_hash = $2
            ON CONFLICT (intent_id, transition_key) DO NOTHING
            ",
        )
        .bind(intent_id)
        .bind(transaction_hash)
        .bind(transition_key)
        .bind(current_status)
        .bind(status.as_str())
        .bind(block_number_db)
        .bind(block_hash)
        .execute(&mut *transaction)
        .await
        .map_err(|e| anyhow::anyhow!("Failed to record execution transition: {e}"))?;

        transaction
            .commit()
            .await
            .map_err(|e| anyhow::anyhow!("Failed to commit execution transition: {e}"))?;
        Ok(())
    }

    /// Loads the active intent owned by a signer, if one exists.
    ///
    /// # Errors
    ///
    /// Returns an error if the query fails.
    pub async fn get_active_execution_intent(
        &self,
        chain_id: u32,
        wallet_address: &str,
    ) -> anyhow::Result<Option<ExecutionIntentRow>> {
        let chain_id_db = i32::try_from(chain_id)
            .with_context(|| format!("Chain ID {chain_id} exceeds PostgreSQL INTEGER"))?;
        sqlx::query_as::<_, ExecutionIntentRow>(
            "
            SELECT

View on GitHub (pinned to 2114cf6f76)

Solutions

  1. Treat a commit error as 'outcome unknown' and simply retry record_execution_status with the same arguments - idempotency keys make the replay safe
  2. Check Postgres logs to confirm whether the transaction committed if you need certainty before retrying
  3. If commits fail repeatedly, investigate connection stability (TCP keepalives, PgBouncer transaction pooling vs session state, Postgres restarts)
  4. Avoid wrapping the call in an outer transaction that is itself long-lived; keep begin-to-commit windows short

Example fix

// before: commit failure is fatal to the watcher loop
let _ = db.record_execution_status(intent_id, hash, status, block, block_hash, ok, gas, price).await?;

// after: a failed commit is ambiguous -> replay once and let ON CONFLICT (intent_id, transition_key) dedupe
match db.record_execution_status(intent_id, hash, status, block, block_hash, ok, gas, price).await {
    Ok(()) => Ok(()),
    Err(e) if matches!(e.downcast_ref::<sqlx::Error>(), Some(sqlx::Error::Io(_))) => {
        db.record_execution_status(intent_id, hash, status, block, block_hash, ok, gas, price).await
    }
    Err(e) => Err(e),
}
Defensive patterns

Strategy: retry

Type guard

fn is_commit_ambiguity(err: &anyhow::Error) -> bool {
    matches!(
        err.downcast_ref::<sqlx::Error>(),
        Some(sqlx::Error::Io(_)) | None // None = driver-level disconnect wrappers
    )
}

Try / catch

match db.record_execution_status(...).await {
    Ok(()) => Ok(()),
    Err(e) if is_commit_ambiguity(&e) => {
        // outcome unknown: replay once; transition_key ON CONFLICT dedupes if it committed
        db.record_execution_status(...).await
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Connection dropping exactly at commit; Postgres restarting or being failed over; a serialization failure surfacing at commit; the pool recycling a broken connection under the transaction.

Common situations: Network blips between the trading host and Postgres; Postgres maintenance restarts during receipt processing; aggressive idle-in-transaction timeouts killing the session before commit.

Related errors


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