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_header

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the bootstrap checkpoint (checkpoint_hash, checkpoint_parent_hash, timestamp, base_fee) matches the actual chain — recompute from a trusted beacon/execution source.
  2. Check chain_id and wallet_address in your configuration; the ledger keys on (chain_id, wallet_address, number) and mixing environments causes collisions.
  3. 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.
  4. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/0432cb92b7d101f3. Report an issue: GitHub.