nautechsystems/nautilus_trader · critical · anyhow::Error
Finalized checkpoint ledger conflicts with the trusted chain
Error message
Finalized checkpoint ledger conflicts with the trusted chain anchor
What it means
This is an integrity violation raised by anyhow::ensure! after comparing the stored checkpoint row against the trusted bootstrap anchor. If the durable row's (hash, parent_hash, timestamp, base_fee_per_gas) tuple does not exactly equal the trusted checkpoint supplied in the bootstrap payload, the library refuses to proceed: the local ledger's chain anchor disagrees with the expected chain, which would silently fork or corrupt verification state.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:4404
.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(),
checkpoint_timestamp,
bootstrap
.checkpoint_base_fee_per_gas
.map(|value| value.to_string()),
),
"Finalized checkpoint ledger conflicts with the trusted chain anchor"
);
if initialized {
let stored_tip =
sqlx::query_as::<_, (i64, String, String, i64, Option<String>, String)>(
"
SELECT number, hash, parent_hash, timestamp, base_fee_per_gas, manifest_digest
FROM execution_verified_finalized_headerView on GitHub (pinned to 18893faf8b)
Solutions
- Verify the bootstrap checkpoint (checkpoint_hash, checkpoint_parent_hash, timestamp, base_fee) matches the actual chain — recompute from a trusted beacon/execution source.
- Check chain_id and wallet_address in your configuration; the ledger keys on (chain_id, wallet_address, number) and mixing environments causes collisions.
- Inspect the existing row: SELECT * FROM execution_verified_finalized_header WHERE chain_id=$1 AND wallet_address=$2 AND number=$3; if it is from stale/wrong data, move it to a new database or purge that wallet's ledger rows deliberately and re-bootstrap.
- Do not manually edit rows to make the comparison pass — that defeats the integrity check.
Example fix
// before — mismatch surfaces only at runtime
anyhow::ensure!(
stored_checkpoint == (bootstrap.checkpoint_hash.to_string(), /* ... */),
"Finalized checkpoint ledger conflicts with the trusted chain anchor"
);
// after — validate the anchor before opening the write transaction
let existing: Option<(String, String, i64, Option<String>)> = sqlx::query_as(/* SELECT ... */)
.bind(chain_id)
.bind(bootstrap.wallet_address)
.bind(bootstrap.checkpoint_number)
.fetch_optional(&mut *transaction)
.await?;
if let Some(row) = existing {
anyhow::ensure!(
row.0 == bootstrap.checkpoint_hash.to_string(),
"Checkpoint {} for chain {chain_id} is {} but bootstrap anchor is {} — use a fresh database or the matching chain config",
bootstrap.checkpoint_number, row.0, bootstrap.checkpoint_hash
);
} Defensive patterns
Strategy: validation
Validate before calling
// Validate the anchor against the DB BEFORE the bootstrap write path
let existing: Option<(String,)> = sqlx::query_as(
"SELECT hash FROM execution_verified_finalized_header WHERE chain_id=$1 AND wallet_address=$2 AND number=$3",
).bind(chain_id).bind(wallet).bind(checkpoint_number).fetch_optional(&pool).await?;
if let Some((hash,)) = existing {
anyhow::ensure!(
hash == expected_checkpoint_hash,
"DB checkpoint {checkpoint_number} is {hash}, config anchor is {expected_checkpoint_hash} — align chain config or use a fresh database"
);
} Type guard
fn matches_trusted_anchor(stored: &(String, String, i64, Option<String>), b: &Bootstrap) -> bool {
stored.0 == b.checkpoint_hash.to_string()
&& stored.1 == b.checkpoint_parent_hash.to_string()
&& stored.3.as_deref() == b.checkpoint_base_fee_per_gas.map(|v| v.to_string()).as_deref()
} Try / catch
match bootstrap_result {
Err(e) if e.to_string().contains("conflicts with the trusted chain anchor") => {
error!("Ledger anchored to a different chain — verify chain_id/network config, do NOT edit rows to force a match");
std::process::exit(1);
}
other => other,
} Prevention
- Key each environment (mainnet/testnet/dev) on a separate database so chain data never mixes
- Never change the trusted checkpoint hash/timestamp after a ledger is initialized
- Never hand-edit ledger rows to satisfy the comparison
- Verify the bootstrap checkpoint against a trusted beacon source before configuring it
When it happens
Trigger: Bootstrapping a wallet/chain whose stored checkpoint at `checkpoint_number` was written from a different chain (e.g. testnet data in a mainnet database), a reorged or different checkpoint supplied in bootstrap config, or manual tampering/repair of the ledger table.
Common situations: Pointing the adapter at a database previously used with a different network or chain_id/wallet; changing the trusted checkpoint configuration after initialization; a bad snapshot/restore leaving rows from another deployment; hand-edited rows.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- Verified finalized transaction count advanced without an act
- RPC tick {tick_value} does not match positions: derived gros
- Fetched block {} while requesting RPC snapshot block {}
- {context} verification disagreed
- Canonical nonce advanced without an authenticated signer tra
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/0432cb92b7d101f3.
Report an issue: GitHub.