nautechsystems/nautilus_trader · error · anyhow::Error

Failed to commit execution transition

Error message

Failed to commit execution transition: {e}

What it means

Raised when transaction.commit() fails after all statements in the execution-status transition succeeded. Nothing is persisted (the transaction rolls back implicitly), even though row locks, validation, and writes all passed locally. This typically indicates the connection to the database was lost between the last statement and the commit.

Solutions

  1. Retry the entire transition with backoff — the rollback left state consistent, so a retry is safe.
  2. Shorten the transaction (do non-critical work outside it) to stay under idle-in-transaction timeouts.
  3. Tune Postgres idle_in_transaction_session_timeout and the pool's acquire/idle timeouts for the workload.
  4. Check server logs for 'terminating connection' or deadlock messages at the failure timestamp.

Example fix

// before
transaction.commit().await.map_err(|e| anyhow::anyhow!("Failed to commit execution transition: {e}"))?;
// after
if let Err(e) = transaction.commit().await {
    tracing::warn!(error = %e, "commit failed; state unchanged, safe to retry");
    return Err(anyhow::anyhow!("Failed to commit execution transition: {e}"));
}
Defensive patterns

Strategy: retry

Try / catch

loop {
    match transition.await {
        Ok(()) => break,
        Err(e) if e.to_string().contains("Failed to commit execution transition") && attempts < MAX_RETRIES => {
            attempts += 1;
            tokio::time::sleep(backoff.next()).await; // rollback left state consistent
        }
        Err(e) => return Err(e),
    }
}

Prevention

When it happens

Trigger: Calling the transition when COMMIT fails: network drop or database restart mid-transaction, idle_in_transaction_session_timeout terminating the session after long lock waits, admin-initiated pg_terminate_backend, or serialization/deadlock detection aborting the commit.

Common situations: Long lock contention on the intent row (another worker holding FOR UPDATE) pushing past the session timeout; database failover during receipt processing; firewall/NAT dropping idle connections between statements.

Related errors


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

Appendix: source

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

            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(())
    }

    /// Records verified final consumption and advances the canonical nonce in one transaction.
    ///
    /// # Errors
    ///
    /// Returns an error if the receipt transition, nonce ledger, manifest identity, or evidence
    /// is inconsistent, or if persistence fails.
    pub(crate) async fn record_execution_finality_verified(
        &self,
        finality: &ExecutionFinalityTransition<'_>,
    ) -> anyhow::Result<()> {
        anyhow::ensure!(
            matches!(
                finality.status,
                TransactionStatus::Finalized | TransactionStatus::Reverted
            ),

View on GitHub (pinned to 18893faf8b)