nautechsystems/nautilus_trader · critical

Verified finalized header conflicts with its ancestry window

Error message

Verified finalized header conflicts with its ancestry window

What it means

After replaying the ancestry window of headers between the durable finalized tip and the newly verified finalized header, the cursor must land exactly on the verified finalized header. If it does not, one of the intermediate headers breaks the chain of ancestry (hash linkage), meaning the verified header is not a descendant of the stored tip.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:6041

            let start = ancestry_cursor.number.saturating_add(1);
            let headers_verification = required_verification(
                self.verification
                    .verify_header_window(ancestry_cursor, end)
                    .await,
                "Blockchain finalized ancestry",
            )?;
            let headers = &headers_verification.value;
            ancestry_cursor = *headers
                .last()
                .expect("nonempty ancestry window advances the cursor");
            finalized_headers.extend(headers.iter().copied());
            connect_decisions.push(verification_decision(
                &headers_verification,
                Some(start),
                Some(end),
            ));
        }
        anyhow::ensure!(
            ancestry_cursor == finalized,
            "Verified finalized header conflicts with its ancestry window"
        );
        let nonce_verification = required_verification(
            self.verification
                .verify_transaction_count(&self.wallet_address, finalized.number)
                .await,
            "Blockchain finalized transaction count",
        )?;
        let observed_canonical_nonce = nonce_verification.value;
        let next_canonical_nonce = position
            .as_ref()
            .map_or(observed_canonical_nonce, |position| {
                position.next_canonical_nonce
            });

        if let Some(position) = position.as_ref() {
            log::debug!(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Rebuild the finalized header ancestry from the trusted checkpoint to discard reorged/corrupt headers.
  2. Verify the verification provider returns a consistent, hash-linked header chain (single provider, correct network).
  3. Check for mid-window reorgs and restart connection once finality stabilizes above the affected heights.
  4. Log/compare cursor hash vs finalized parent hash to locate the first divergent header before resyncing.

Example fix

// before: alternating providers across ancestry windows can yield unlinked headers
provider = round_robin([rpc_a, rpc_b])

// after: use one consistent provider per connect
provider = rpc_a
Defensive patterns

Strategy: validation

Validate before calling

let linked = ancestry.windows(2).all(|w| w[1].parent_hash == w[0].hash());
assert!(linked, "ancestry window is not hash-linked");

Type guard

fn ancestry_consistent(cursor: &Header, finalized: &Header) -> bool { cursor.hash() == finalized.hash() && cursor.number == finalized.number }

Try / catch

match client.connect().await {
    Err(e) if e.to_string().contains("ancestry window") => rebuild_ancestry_from_checkpoint().await,
    other => other.map(|_| ()),
}

Prevention

When it happens

Trigger: The while loop fetches consecutive header windows (verify via self.verification.verify_block / headers_verification decisions) from durable tip to finalized.number; the final ancestry_cursor != finalized, firing ensure!.

Common situations: A reorg replaced headers between the stored tip and the verified finalized height, an inconsistent verification provider returning headers that do not link, or corrupted cached headers within the ancestry window.

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


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