nautechsystems/nautilus_trader · error · anyhow::Error

Failed to commit verified finality transition: {e}

Error message

Failed to commit verified finality transition: {e}

What it means

This error wraps a failure of transaction.commit() at the end of the verified-finality flow (database.rs:7199). All statements succeeded but the atomic commit to PostgreSQL failed, so the entire transition (finality receipt, intent status, transition row, nonce advance) rolls back and nothing is persisted.

Source

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

              AND next_canonical_nonce = $4 AND revision = $5
            ",
        )
        .bind(chain_id)
        .bind(finality.wallet_address)
        .bind(next_nonce)
        .bind(nonce)
        .bind(revision)
        .execute(&mut *transaction)
        .await
        .map_err(|e| anyhow::anyhow!("Failed to advance canonical nonce ledger: {e}"))?;
        anyhow::ensure!(
            nonce_result.rows_affected() == 1,
            "Canonical nonce ledger changed during finality transition"
        );
        transaction
            .commit()
            .await
            .map_err(|e| anyhow::anyhow!("Failed to commit verified finality transition: {e}"))?;
        Ok(())
    }

    /// Loads one durable execution intent by ID.
    pub(crate) async fn get_execution_intent(
        &self,
        intent_id: i64,
    ) -> anyhow::Result<ExecutionIntentRow> {
        sqlx::query_as::<_, ExecutionIntentRow>(
            "
            SELECT
                id, schema_version, chain_id, wallet_address, nonce, purpose, status,
                client_order_id, trader_id, strategy_id, account_id, instrument_id,
                pool_address, transaction_to, transaction_input, transaction_value,
                amount_in, created_block, acknowledgement_emitted, fill_emitted,
                terminal_emitted, active
            FROM execution_intent
            WHERE id = $1

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Retry the entire finality transition with a fresh transaction — commit failure is atomic, so state is unchanged and a retry is safe.
  2. Reduce transaction duration (check network latency, move non-DB work outside the transaction) to avoid idle-in-transaction timeouts.
  3. Verify database health/uptime at the failure timestamp; check for failover or restarts in Postgres logs.
  4. Tune pool settings (acquire timeout, max lifetime) so connections are not closed mid-transaction.
  5. Inspect Postgres logs for deadlock or serialization-failure SQLSTATEs and coordinate lock ordering with other writers.

Example fix

// before: treating commit failure as partial success
if let Err(e) = res { log::warn!("finality commit: {e}"); }
// after: retry the whole transactional operation
let res = db.record_verified_finality(&finality).await;
match res {
    Err(e) if is_transient(&e) => db.record_verified_finality(&finality).await.context("finality retry")?,
    other => other?,
}
Defensive patterns

Strategy: retry

Validate before calling

let healthy: bool = sqlx::query_scalar("SELECT 1 = 1").fetch_one(&pool).await.is_ok();
if !healthy { return Err(anyhow!("database unreachable; defer finality commit")); }

Type guard

fn is_commit_failure(e: &anyhow::Error) -> bool {
    e.to_string().contains("Failed to commit verified finality transition")
}

Try / catch

match res {
    Err(e) if is_commit_failure(&e) && attempt < MAX_RETRIES => {
        warn!("commit failed, retrying atomically: {e}");
        return retry_whole_transition().await;
    }
    other => other,
}

Prevention

When it happens

Trigger: The COMMIT statement fails: the database connection was lost or restarted between the last statement and commit, a serialization/deadlock error was raised at commit time, the statement/idle-in-transaction timeout expired during a long transaction, or the pool forcibly closed the connection.

Common situations: Long-running finality transactions hitting idle_in_transaction_session_timeout on managed Postgres (RDS/Cloud SQL); network partition or failover mid-transaction; connection pool recycling while a transaction is open; Postgres under heavy lock contention deadlocking with another writer.

Related errors


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