nautechsystems/nautilus_trader · error
verified finalized headers are nonempty
Error message
verified finalized headers are nonempty
What it means
While loading a bootstrap, the code takes the last element of `bootstrap.finalized_headers` and panics with "verified finalized headers are nonempty" if the list is empty. This is an internal invariant: headers that were verified upstream are expected to always contain at least one (the latest finalized) header.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:4515
.map_err(|e| anyhow::anyhow!("Failed to validate finalized header ledger: {e}"))?;
anyhow::ensure!(
stored
== (
header.hash.clone(),
header.parent_hash.clone(),
timestamp,
base_fee,
bootstrap.manifest_digest.to_string(),
),
"Finalized header ledger conflicts at height {}",
header.number
);
}
let finalized_height = bootstrap
.finalized_headers
.last()
.expect("verified finalized headers are nonempty")
.number;
for (index, decision) in bootstrap.decisions.iter().enumerate() {
let height_start = decision
.height_start
.map(i64::try_from)
.transpose()
.context("Connect verification height exceeds PostgreSQL BIGINT")?;
let height_end = decision
.height_end
.map(i64::try_from)
.transpose()
.context("Connect verification height exceeds PostgreSQL BIGINT")?;
let transition_key = format!("connect:{finalized_height}:{revision}:{index}");
sqlx::query(
"
INSERT INTO execution_verification_decision (
intent_id, nonce, decision_class, read_class, height_start, height_end,View on GitHub (pinned to 18893faf8b)
Solutions
- Check the checkpoint/bootstrap provider is returning finalized headers and that the fetch succeeded.
- Verify the verification step actually populated `finalized_headers` before reaching this code.
- If you control the caller, validate `!finalized_headers.is_empty()` earlier and surface a proper error instead of panicking.
- Update/patch the adapter if the upstream verification invariant is broken in your version.
Example fix
// before
let finalized_height = bootstrap.finalized_headers.last()
.expect("verified finalized headers are nonempty").number;
// after
let Some(latest) = bootstrap.finalized_headers.last() else {
return Err(anyhow!("bootstrap returned no finalized headers"));
};
let finalized_height = latest.number; Defensive patterns
Strategy: validation
Validate before calling
if bootstrap.finalized_headers.is_empty() {
return Err(anyhow!("bootstrap returned no finalized headers"));
} Type guard
fn has_finalized_headers(b: &Bootstrap) -> bool { !b.finalized_headers.is_empty() } Try / catch
// Rust: convert panic into a Result by checking last() yourself
let Some(latest) = bootstrap.finalized_headers.last() else {
return Err(anyhow!("no finalized headers in bootstrap"));
}; Prevention
- Validate bootstrap payloads (non-empty finalized headers) immediately after fetch.
- Use a reputable checkpoint/finality provider and verify fetch success.
- Keep the consensus adapter updated; report empty-header responses upstream.
When it happens
Trigger: A bootstrap response whose `finalized_headers` vector is empty despite having been through verification — e.g. a checkpoint/provider returning no finalized headers, or a corrupted/partial bootstrap payload.
Common situations: Syncing against a weak-subjectivity checkpoint source that returns no finalized headers; upstream verification logic bug; truncated bootstrap data from an RPC/consensus provider.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- in-flight mutex poisoned
- wallet balance mutex poisoned
- Unsupported blockchain {blockchain} for RPC connection
- Finalized header verification disagreed
- Finalized header verification is locally invalid
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/d671ce3e0ee962c6.
Report an issue: GitHub.