nautechsystems/nautilus_trader · error · anyhow::Error
Verified finalized header ledger is not continuous
Error message
Verified finalized header ledger is not continuous
What it means
After deserializing the verified finalized-header ledger, the library verifies the chain is continuous: it must be non-empty and every header must extend the previous one (number incremented by exactly 1 and parent_hash equal to the previous header's hash). This error is thrown when those invariants fail, because a discontinuous ledger cannot be trusted for execution verification.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:7742
);
Ok(ExecutionVerifiedHeader {
number: u64::try_from(number)
.context("Finalized header number is negative")?,
hash,
parent_hash,
timestamp: u64::try_from(timestamp)
.context("Finalized header timestamp is negative")?,
base_fee_per_gas: base_fee
.map(|value| {
value.parse::<u128>().map_err(|_| {
anyhow::anyhow!("Finalized header base fee is invalid")
})
})
.transpose()?,
})
})
.collect::<anyhow::Result<Vec<_>>>()?;
anyhow::ensure!(
!finalized_headers.is_empty()
&& finalized_headers.windows(2).all(|headers| {
headers[1].number == headers[0].number.saturating_add(1)
&& headers[1].parent_hash == headers[0].hash
}),
"Verified finalized header ledger is not continuous"
);
Ok(Some(ExecutionVerificationResume {
next_canonical_nonce: u64::try_from(nonce)
.context("Canonical nonce is negative")?,
revision: u64::try_from(revision)
.context("Canonical nonce revision is negative")?,
finalized_headers,
}))
}
}
#[tokio::test]View on GitHub (pinned to 18893faf8b)
Solutions
- Re-ingest the full finalized-header ledger from the chain under the current manifest so the sequence is rebuilt contiguously
- Restore the ledger from a backup taken before the discontinuity was introduced
- Identify the gap/mismatch (compare consecutive number/parent_hash values) and backfill the missing headers in order
- Never delete individual rows; truncate the whole ledger and repopulate atomically if cleanup is needed
Example fix
// before DELETE FROM finalized_headers WHERE number = 101; -- creates a gap // after TRUNCATE finalized_headers; -- then rebuild the full contiguous ledger from source
Defensive patterns
Strategy: try-catch
Validate before calling
let gaps = sqlx::query("
SELECT a.number FROM finalized_headers a
LEFT JOIN finalized_headers b ON b.number = a.number + 1
WHERE b.number IS NULL")
.fetch_all(&pool).await?;
if !gaps.is_empty() { eprintln!("ledger discontinuities at {:?}", gaps); } Type guard
fn ledger_is_continuous(headers: &[ExecutionVerifiedHeader]) -> bool {
!headers.is_empty()
&& headers.windows(2).all(|w| {
w[1].number == w[0].number + 1 && w[1].parent_hash == w[0].hash
})
} Try / catch
match load_finalized_ledger(digest).await {
Err(e) if e.to_string().contains("not continuous") => {
// truncate and rebuild the ledger from the chain
}
other => other?,
} Prevention
- Never delete individual ledger rows; rebuild atomically
- Write ledger rows in ordered batches within one transaction
- Detect reorgs/forks before appending headers
- Run continuity checks as a periodic integrity job
When it happens
Trigger: Loading a ledger with zero rows, rows with gaps in numbers (e.g. 100, 102), or rows whose parent_hash does not match the previous row's hash — typically after manual deletes, a partial re-ingestion, or mixing rows from different manifests/chains.
Common situations: Deleting individual header rows to 'clean up' the table; a failed backfill that skipped blocks; rows from a reorged or forked chain interleaved with the canonical ledger; a wiped table being partially repopulated.
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
- Replacement scan conflicts with the durable finalized header
- Verified finalized transaction count advanced without an act
- Verified finalized transaction count is outside the owned re
- Verified finalized header extension does not start at the du
- Finalized header ledger conflicts at height {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/d3eaa695d64a8e2c.
Report an issue: GitHub.