nautechsystems/nautilus_trader · error · anyhow::Error
Failed to start execution status transition
Error message
Failed to start execution status transition: {e} What it means
This error wraps a failure to BEGIN a SQL transaction via sqlx's pool when starting an execution-status transition in the blockchain cache database. The transaction is needed to row-lock (SELECT ... FOR UPDATE) the execution_intent row and apply the state change atomically. If the pool cannot start a transaction (connection unavailable, pool exhausted, database down), the transition is aborted with this message.
Solutions
- Verify the database is reachable and credentials are correct (psql with the same DATABASE_URL).
- Check pool sizing (max_connections, acquire_timeout) versus concurrent load; increase limits or reduce concurrency.
- Retry the operation with backoff — sqlx pool acquisition failures are often transient.
- Inspect the inner `{e}` message for the root sqlx error (connection refused vs timeout vs auth).
Example fix
// before
let mut transaction = self.pool.begin().await.map_err(|e| anyhow::anyhow!("Failed to start execution status transition: {e}"))?;
// after
let mut transaction = self.pool
.begin()
.await
.with_context(|| format!("Failed to start execution status transition (db={})", self.pool.size()))?; Defensive patterns
Strategy: retry
Validate before calling
// Rust: check pool health before attempting the transition
if self.pool.is_closed() {
anyhow::bail!("database pool closed");
}
// optionally: let _ = sqlx::query("SELECT 1").execute(&self.pool).await?; Try / catch
match db.record_execution_status(&intent_id, status, ...).await {
Ok(()) => {},
Err(e) if e.to_string().contains("Failed to start execution status transition") => {
tracing::warn!(error = %e, "transient db error; retrying with backoff");
tokio::time::sleep(backoff.next()).await;
}
Err(e) => return Err(e),
} Prevention
- Size the connection pool for peak concurrency and set a sane acquire_timeout.
- Run periodic SELECT 1 health checks to recycle stale pool connections.
- Alert on database reachability so transitions fail fast during outages.
When it happens
Trigger: Calling the execution-status transition method (e.g. record_execution_status/transition) when DatabasePool::begin() fails: connection pool exhausted (max_connections in use), database unreachable, connection dropped mid-handshake, or TLS/auth failure at connect time.
Common situations: Database restarted or failover in progress while the adapter processes receipts; pool saturation under high event throughput; wrong DATABASE_URL / credentials after a config change; network partition between the adapter and Postgres; idle connections reaped by a firewall/load balancer.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- Failed to advance canonical nonce ledger
- Failed to commit execution transition
- Failed to commit verified action evidence
- Failed to commit verified finality transition
- Failed to delete position_event rows
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/70822522b3c9caf0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/blockchain/src/cache/database.rs:6783
.map(i64::try_from)
.transpose()
.with_context(|| {
format!(
"Execution block number {} exceeds PostgreSQL BIGINT",
block_number.unwrap_or_default()
)
})?;
let gas_used_db = gas_used.map(i64::try_from).transpose().with_context(|| {
format!(
"Execution gas used {} exceeds PostgreSQL BIGINT",
gas_used.unwrap_or_default()
)
})?;
let mut transaction = self
.pool
.begin()
.await
.map_err(|e| anyhow::anyhow!("Failed to start execution status transition: {e}"))?;
let (current_status, fill_emitted, terminal_emitted) =
sqlx::query_as::<_, (String, bool, bool)>(
"SELECT status, fill_emitted, terminal_emitted FROM execution_intent WHERE id = $1 FOR UPDATE",
)
.bind(intent_id)
.fetch_optional(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to lock execution intent {intent_id}: {e}"))?
.ok_or_else(|| anyhow::anyhow!("Execution intent {intent_id} was not found"))?;
anyhow::ensure!(
execution_transition_allowed(¤t_status, status),
"Invalid execution transition for intent {intent_id}: {current_status} -> {}",
status.as_str()
);
let active = match status {
TransactionStatus::Finalized | TransactionStatus::Reverted => {
!fill_emitted && !terminal_emittedView on GitHub (pinned to 18893faf8b)