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>(
"
SELECTView on GitHub (pinned to 2114cf6f76)
Solutions
- Treat a commit error as 'outcome unknown' and simply retry record_execution_status with the same arguments - idempotency keys make the replay safe
- Check Postgres logs to confirm whether the transaction committed if you need certainty before retrying
- If commits fail repeatedly, investigate connection stability (TCP keepalives, PgBouncer transaction pooling vs session state, Postgres restarts)
- 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
- Design every multi-statement cache flow to be replayable (idempotency keys like transition_key) so commit ambiguity is resolved by retry
- Enable TCP keepalives and avoid idle-in-transaction downtime between statements and commit
- Do not wrap library calls in outer transactions; nested commit paths make ambiguity worse
- After repeated commit failures, verify Postgres health before replaying into it
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
- Failed to commit replacement transaction: {e}
- Execution intent {intent_id} cannot mark {event} emitted
- Failed to update execution hash {transaction_hash}: {e}
- Execution transaction hash {transaction_hash} was not found
- Failed to update execution intent {intent_id}: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21).
Data as JSON: /api/errors/7704165812654471.
Report an issue: GitHub.