nautechsystems/nautilus_trader · error
Durable finalized header tip precedes the trusted checkpoint
Error message
Durable finalized header tip precedes the trusted checkpoint
What it means
The execution client recovered its durable finalized tip from the verification ledger, but the stored header's block number is lower than the trusted checkpoint the run is anchored to. NautilusTrader requires durable finality to be at least as advanced as the checkpoint, so a stale or rolled-back ledger means the durable state cannot safely supplement checkpoint trust and the operation is aborted.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:3433
)?;
let checkpoint = checkpoint_verification.value;
let mut decisions = vec![verification_decision(
&checkpoint_verification,
Some(checkpoint.number),
Some(checkpoint.number),
)];
let position = self
.database
.load_execution_verification_position(
self.chain_id,
&self.wallet_address.to_string(),
&self.manifest_version,
&self.manifest_digest,
)
.await?
.ok_or_else(|| anyhow::anyhow!("Execution verification ledger is not initialized"))?;
let durable_tip = parse_verified_header(&position.finalized_tip)?;
anyhow::ensure!(
durable_tip.number >= checkpoint.number,
"Durable finalized header tip precedes the trusted checkpoint"
);
let mut finalized_headers = vec![durable_tip];
let durable_tip_verification = required_verification(
self.verification.verify_block(durable_tip.number).await,
"finality durable header tip",
)?;
anyhow::ensure!(
durable_tip_verification.value == durable_tip,
"Durable finalized header tip conflicts with independent sources"
);
decisions.push(verification_decision(
&durable_tip_verification,
Some(durable_tip.number),
Some(durable_tip.number),
));
anyhow::ensure!(View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect the verification ledger's finalized tip and compare its block number to the configured trusted checkpoint.
- Rebuild or resync the verification ledger so its finalized tip is at or beyond the checkpoint (e.g. replay finalized headers from the RPC provider).
- Re-run the recovery after the ledger has caught up, or re-anchor the run at an older checkpoint consistent with the ledger.
Example fix
// before: checkpoint ahead of ledger state let checkpoint = load_checkpoint(); // # 1_000 // ledger finalized_tip.number == 900 -> ensure! fails // after: resync ledger, then verify before recovery ensure_durable_tip_covers_checkpoint(&ledger, &checkpoint)?; // tip >= checkpoint
Defensive patterns
Strategy: validation
Validate before calling
// before recovery, assert ledger covers checkpoint
let tip_number = ledger.finalized_tip_number()?;
anyhow::ensure!(tip_number >= checkpoint.number, "ledger tip {} < checkpoint {}", tip_number, checkpoint.number); Try / catch
match client.recover_finality(&checkpoint).await {
Err(e) if e.to_string().contains("precedes the trusted checkpoint") => resync_ledger_and_retry(),
Err(e) => return Err(e),
Ok(v) => Ok(v),
} Prevention
- Resync the verification ledger whenever the checkpoint is advanced
- Never restore ledger snapshots older than the configured checkpoint
- Add a startup health check comparing ledger tip vs checkpoint
When it happens
Trigger: Calling transaction finality recovery when the verification ledger row `finalized_tip` holds a header whose number < the checkpoint number — typically after restoring an older ledger snapshot, a partial ledger write/rollback, or pointing the client at a database populated against a different (older) checkpoint.
Common situations: Failover to a replica with a lagging verification ledger; restoring a DB backup from before the checkpoint was advanced; mixing ledger state from a previous deployment with a newer configured trusted checkpoint; ledger pruning that removed recent finalized headers.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Retained terminal receipt is not on the verified finalized a
- Finalized execution transaction {tx_hash} no longer has a re
- Finalized block {} changed from {} to {} before intent valid
- Finalized block {} changed from {} to {} before fill emissio
- Verified finalized transaction count advanced without an act
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/3d43df7df218303d.
Report an issue: GitHub.