nautechsystems/nautilus_trader · error · anyhow::Error
Failed to initialize finalized header ledger: {e}
Error message
Failed to initialize finalized header ledger: {e} What it means
This error wraps a sqlx failure on the INSERT that seeds the `execution_verified_finalized_header` ledger with the trusted checkpoint header (ON CONFLICT DO NOTHING). The bootstrap path writes the checkpoint row inside a transaction before validating it; any database-level failure on that INSERT is re-raised with this message and aborts ledger initialization.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:4390
INSERT INTO execution_verified_finalized_header (
chain_id, wallet_address, number, hash, parent_hash, timestamp,
base_fee_per_gas, manifest_digest
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
ON CONFLICT (chain_id, wallet_address, number) DO NOTHING
",
)
.bind(chain_id)
.bind(bootstrap.wallet_address)
.bind(checkpoint_number)
.bind(bootstrap.checkpoint_hash)
.bind(bootstrap.checkpoint_parent_hash)
.bind(checkpoint_timestamp)
.bind(base_fee)
.bind(bootstrap.manifest_digest)
.execute(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to initialize finalized header ledger: {e}"))?;
let stored_checkpoint = sqlx::query_as::<_, (String, String, i64, Option<String>)>(
"
SELECT hash, parent_hash, timestamp, base_fee_per_gas
FROM execution_verified_finalized_header
WHERE chain_id = $1 AND wallet_address = $2 AND number = $3
",
)
.bind(chain_id)
.bind(bootstrap.wallet_address)
.bind(checkpoint_number)
.fetch_one(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to validate finalized checkpoint ledger: {e}"))?;
anyhow::ensure!(
stored_checkpoint
== (
bootstrap.checkpoint_hash.to_string(),
bootstrap.checkpoint_parent_hash.to_string(),View on GitHub (pinned to 18893faf8b)
Solutions
- Apply the crate's schema migrations so `execution_verified_finalized_header` exists with columns (chain_id, wallet_address, number, hash, parent_hash, timestamp, base_fee_per_gas, manifest_digest).
- Read the wrapped sqlx error after the colon for the root cause (undefined table, out-of-range value, connection error).
- Confirm checkpoint_number and checkpoint_timestamp fit into i64 before bootstrapping.
- Check database connectivity, credentials, and pool configuration.
- Retry initialization after a transient failure — the ON CONFLICT DO NOTHING makes re-runs idempotent.
Example fix
// before
.execute(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to initialize finalized header ledger: {e}"))?;
// after
.execute(&mut *transaction)
.await
.map_err(|e| {
anyhow::anyhow!(
"Failed to initialize finalized header ledger at number {checkpoint_number}: {e:#}"
)
})?; Defensive patterns
Strategy: retry
Validate before calling
// Verify schema readiness before bootstrap
let ready: bool = sqlx::query_scalar(
"SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name='execution_verified_finalized_header')",
).fetch_one(&pool).await?;
anyhow::ensure!(ready, "verified header table missing; run migrations");
anyhow::ensure!(
bootstrap.checkpoint_number <= i64::MAX as u64,
"checkpoint number exceeds BIGINT"
); Try / catch
match bootstrap_result {
Err(e) if is_transient_db_error(&e) => {
warn!("transient DB error, retrying bootstrap: {e:#}");
backoff_retry(|| initialize_ledger(...), 3);
}
Err(e) => return Err(e),
Ok(v) => Ok(v),
} Prevention
- Run schema migrations before starting the adapter
- Use ON CONFLICT DO NOTHING semantics (already built-in) so retries are safe
- Confirm checkpoint number/timestamp fit PostgreSQL BIGINT
- Pin a healthy database_url and validate connectivity at startup
When it happens
Trigger: During finalized-ledger bootstrap when the checkpoint INSERT fails: table `execution_verified_finalized_header` missing or schema-drifted, i64 bind of checkpoint_number/timestamp/base_fee out of range, connection/pool failure, or the transaction already aborted from an earlier step.
Common situations: Deploying a new version of the adapter against an un-migrated database; checkpoint height or base-fee values that exceed BIGINT; transient Postgres restarts or timeouts; wrong database_url pointing at a database without the verified-header tables.
Related errors
- Failed to seed chain table: {e}
- Failed to call create_block_partition for chain {}: {e}
- Failed to call create_token_partition for chain {}: {e}
- Failed to get block info for chain {}: {}
- Failed to insert into block table: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/53499b74ce978cea.
Report an issue: GitHub.