nautechsystems/nautilus_trader · error · anyhow::Error
Failed to commit verified finality transition
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.
Solutions
- Retry the entire finality transition with a fresh transaction — commit failure is atomic, so state is unchanged and a retry is safe.
- Reduce transaction duration (check network latency, move non-DB work outside the transaction) to avoid idle-in-transaction timeouts.
- Verify database health/uptime at the failure timestamp; check for failover or restarts in Postgres logs.
- Tune pool settings (acquire timeout, max lifetime) so connections are not closed mid-transaction.
- 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
- Keep finality transactions short; do no external I/O inside the transaction.
- Set idle_in_transaction_session_timeout above your worst-case transaction duration.
- Retry the entire operation on commit failure — the rollback leaves state consistent.
- Monitor Postgres restarts/failovers and alert on connection churn in pool metrics.
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
- Failed to commit execution transition
- Failed to commit verified action evidence
- Failed to advance canonical nonce ledger
- Failed to commit add_account transaction
- Failed to commit order client origins
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/1193ace80d1df0ca.
Report an issue: GitHub.
Appendix: 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 = $1View on GitHub (pinned to 18893faf8b)