nautechsystems/nautilus_trader · error · anyhow::Error
Failed to start execution verification migration: {e}
Error message
Failed to start execution verification migration: {e} What it means
This error wraps a failure from `self.pool.begin()` while starting the PostgreSQL transaction that performs the execution verification migration (`ensure_execution_verification_schema`). sqlx could not open a transaction on the connection pool, and the underlying sqlx error is embedded in the message as `{e}`. It is a pre-statement failure: none of the schema DDL has run yet.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:3897
&& bootstrap.failure_domain_ids.len() >= 3
&& !bootstrap.decisions.is_empty(),
"Connect verification evidence is incomplete"
);
let chain_id = i32::try_from(bootstrap.chain_id)
.context("Verification chain ID exceeds PostgreSQL INTEGER")?;
let checkpoint_number = i64::try_from(bootstrap.checkpoint_number)
.context("Verification checkpoint exceeds PostgreSQL BIGINT")?;
let checkpoint_timestamp = i64::try_from(bootstrap.checkpoint_timestamp)
.context("Verification checkpoint timestamp exceeds PostgreSQL BIGINT")?;
let next_canonical_nonce = i64::try_from(bootstrap.next_canonical_nonce)
.context("Canonical nonce exceeds PostgreSQL BIGINT")?;
let observed_canonical_nonce = i64::try_from(bootstrap.observed_canonical_nonce)
.context("Observed canonical nonce exceeds PostgreSQL BIGINT")?;
let base_fee = bootstrap
.checkpoint_base_fee_per_gas
.map(|value| value.to_string());
let mut transaction = self.pool.begin().await.map_err(|e| {
anyhow::anyhow!("Failed to start execution verification migration: {e}")
})?;
for statement in [
"
CREATE TABLE IF NOT EXISTS execution_verification_nonce (
chain_id INTEGER NOT NULL REFERENCES chain(chain_id) ON DELETE RESTRICT,
wallet_address TEXT NOT NULL,
manifest_version TEXT NOT NULL CHECK (manifest_version <> ''),
manifest_digest TEXT NOT NULL CHECK (manifest_digest <> ''),
next_canonical_nonce BIGINT NOT NULL CHECK (next_canonical_nonce >= 0),
revision BIGINT NOT NULL DEFAULT 0 CHECK (revision >= 0),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (chain_id, wallet_address)
)
",
"
CREATE TABLE IF NOT EXISTS execution_verified_finalized_header (
chain_id INTEGER NOT NULL,View on GitHub (pinned to 18893faf8b)
Solutions
- Read the wrapped sqlx error in the message: if it says connection refused/timeout, verify PostgreSQL is running and `DATABASE_URL` (host, port, user, password, dbname) is correct.
- Increase the sqlx pool limits (`max_connections`, `acquire_timeout`) or reduce concurrent startup work that starves the pool.
- Check network reachability and TLS configuration between the adapter and the database (firewall rules, security groups, CA certificates).
- If errors are intermittent after idle periods, enable pool idle timeouts/recycling so stale connections are not reused.
Example fix
// before
let pool = PgPool::connect(&database_url).await?; // default pool, small acquire timeout
// after
let pool = PgPoolOptions::new()
.max_connections(10)
.acquire_timeout(std::time::Duration::from_secs(30))
.idle_timeout(std::time::Duration::from_secs(300))
.connect(&database_url)
.await?; Defensive patterns
Strategy: retry
Validate before calling
async fn assert_pool_ready(pool: &sqlx::PgPool) -> Result<(), sqlx::Error> {
let mut tx = pool.begin().await?; // fail early with the raw driver error
tx.rollback().await?;
Ok(())
} Try / catch
match database.ensure_execution_verification_schema(&bootstrap).await {
Err(e) if e.to_string().contains("Failed to start execution verification migration") => {
// inspect wrapped sqlx error; backoff and retry for transient connect/pool-acquire failures
tokio::time::sleep(Duration::from_secs(5)).await;
database.ensure_execution_verification_schema(&bootstrap).await?;
}
Err(e) => return Err(e),
Ok(()) => {}
} Prevention
- Validate DATABASE_URL connectivity with a trivial query before starting the migration path.
- Size the pool (max_connections, acquire_timeout) for concurrent startup workloads.
- Monitor PostgreSQL availability and enable connection recycling to avoid stale pooled connections.
- Retry only transient errors (connection reset, acquire timeout); surface auth/config errors immediately.
When it happens
Trigger: Calling `ensure_execution_verification_schema` when the connection pool cannot begin a transaction — pool exhausted (all connections busy), database unreachable, TLS/auth rejected, or the connection dropped mid-handshake.
Common situations: PostgreSQL is down or restarting during application startup; wrong host/port/password in `DATABASE_URL`; connection pool `max_connections` too small for concurrent startup tasks; firewall or idle timeout severing pooled connections; certificate/TLS misconfiguration.
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 start verified action evidence: {e}
- Failed to commit signed transaction: {e}
- Failed to start execution status transition: {e}
- Failed to start verified finality transition: {e}
- Failed to lock finality nonce ledger: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/b4076d3f2d196ab0.
Report an issue: GitHub.