nautechsystems/nautilus_trader · error
Replacement scan tip conflicts with the verified canonical h
Error message
Replacement scan tip conflicts with the verified canonical head
What it means
When the replacement scan reaches the current verified head (end == head.number), the tip of the scanned block list must exactly equal the already-verified canonical head header. A mismatch means the scanned replacement history and the verified canonical head disagree — evidence of a reorg or an inconsistent data source.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:3115
if end > start {
let window = required_verification(
self.verification
.verify_replacement_window(start_header.value, end)
.await,
"canonical replacement window",
)?;
decisions.push(verification_decision(&window, Some(start + 1), Some(end)));
blocks.extend(window.value);
}
}
let scanned_tip = blocks
.last()
.map(|block| VerifiedBlockHeader::from(block.clone()))
.ok_or_else(|| anyhow::anyhow!("Verified replacement scan returned no blocks"))?;
if end == head.number {
anyhow::ensure!(
scanned_tip == head,
"Replacement scan tip conflicts with the verified canonical head"
);
}
let mut candidates = blocks
.iter()
.flat_map(|block| block.transactions.iter())
.filter(|transaction| {
transaction.from == self.wallet_address && transaction.nonce == nonce
});
let candidate = candidates.next();
anyhow::ensure!(
candidates.next().is_none(),
"Canonical replacement scan found duplicate signer-nonce transactions"
);
let finalized_cursor = self
.databaseView on GitHub (pinned to 18893faf8b)
Solutions
- Re-fetch the head and retry the scan after the chain stabilizes
- Pin to a single consistent RPC endpoint for head and window queries
- Persist/re-verify the head header before comparing with the scan tip
- Investigate for a deep reorg if mismatches persist
Defensive patterns
Strategy: retry
Validate before calling
let head = client.verified_head().await?;
let tip = scanned_blocks.last().map(VerifiedBlockHeader::from);
if end == head.number && tip != Some(head) {
return Err("scan tip diverged from head; re-fetch and retry");
} Try / catch
match result {
Err(e) if e.to_string().contains("conflicts with the verified canonical head") => {
refetch_head_and_retry_with_backoff()
}
other => other,
} Prevention
- Re-verify the head immediately before comparison
- Avoid switching RPC nodes mid-scan
- Add reorg detection before reconciliation
- Delay scans near the head until blocks are finalized
When it happens
Trigger: The last block returned by verify_replacement_window() has a different header than the verified head used to compute the scan end, i.e. the head moved (reorg) or the window fetch returned blocks from another branch.
Common situations: Chain reorg between fetching head and scanning; RPC load balancer serving different branches; stale cached head from the verification provider.
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
- Replacement block conflicts with its canonical header
- Replacement scan cursor conflicts with the finalized header
- Canonical nonce advanced without an authenticated signer tra
- Profiler receipt position does not match its ingestion water
- Profiler log position does not match its ingestion watermark
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/d37d7fc68bf1d6cd.
Report an issue: GitHub.