nautechsystems/nautilus_trader · error · anyhow::Error
Failed to commit signed transaction: {e}
Error message
Failed to commit signed transaction: {e} What it means
The final COMMIT of the persistence transaction failed. All prior work (payload state checks, intent lock, signed row insert, status update, transition record) is rolled back, so the operation can be retried safely, but nothing was persisted. The library wraps the commit error with context.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:6740
"
INSERT INTO execution_transaction_transition (
intent_id, transaction_hash_id, transition_key, from_status, to_status
) VALUES ($1, $2, $3, $4, 'signed')
ON CONFLICT (intent_id, transition_key) DO NOTHING
",
)
.bind(intent_id)
.bind(row.id)
.bind(format!("signed:{transaction_hash}"))
.bind(current_status)
.execute(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to record signed transaction transition: {e}"))?;
transaction
.commit()
.await
.map_err(|e| anyhow::anyhow!("Failed to commit signed transaction: {e}"))?;
Ok(row)
}
/// Records an idempotent transaction observation and advances its intent state.
///
/// # Errors
///
/// Returns an error if the transition is invalid, the hash is unknown, or persistence fails.
#[expect(
clippy::too_many_arguments,
reason = "the parameters are the canonical receipt observation persisted atomically"
)]
pub async fn record_execution_status(
&self,
intent_id: i64,
transaction_hash: &str,
status: TransactionStatus,
block_number: Option<u64>,View on GitHub (pinned to 18893faf8b)
Solutions
- Retry the entire add_execution_transaction call — transactionality guarantees no partial state, and retries are idempotent (ON CONFLICT guards).
- Harden connectivity: keepalives, reasonable pool idle timeouts, and statement_timeout sized to the transaction's work.
- Check for failover events in the database logs around the failure time.
- Split heavy work out of the DB transaction where possible to shorten the commit window.
Defensive patterns
Strategy: retry
Validate before calling
// pre-flight: confirm a trivial transaction can commit before batch signing
let mut tx = pool.begin().await?;
tx.commit().await.context("database cannot commit; aborting signing batch")?; Try / catch
let result = retry(3, backoff(250).jitter(), || async {
db.add_execution_transaction(intent_id, chain_id, hash, sealed).await
}).await;
if let Err(e) = result { error!(%e, "commit failed after retries; verify no partial state — operation is transactional"); } Prevention
- Enable TCP keepalives and sane idle timeouts on the pool to survive long transactions
- Retry whole operations after commit failures — transactionality prevents partial writes
- Watch for DB failovers and pause signing during maintenance windows
- Keep the transaction body small so the commit window stays short
When it happens
Trigger: transaction.commit() errored: connection dropped between the last statement and COMMIT (network blip, pool idle timeout, DB failover), server-side commit failure, or the transaction already aborted server-side due to a timeout.
Common situations: PostgreSQL restart/failover mid-transaction; load balancer terminating long-idle connections; very large sealed payloads extending transaction duration past network idle limits; infrastructure churn during deployments.
Related errors
- Failed to commit execution schema migration: {e}
- Failed to start execution verification migration: {e}
- Failed to commit verified nonce assignment: {e}
- Failed to commit verified action evidence: {e}
- Failed to commit execution transition: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/13cb2463e93aa9c2.
Report an issue: GitHub.