nautechsystems/nautilus_trader · error · anyhow::Error
Swap decision header conflicts with profiler ancestry
Error message
Swap decision header conflicts with profiler ancestry
What it means
After fetching the canonical decision header, the library walks the header ancestry from the profiler watermark block to the decision head via verify_header_window. The last ancestry header must be exactly the decision head; otherwise the verified window disagrees with the header used for the swap decision, indicating a reorg or inconsistent verification results. Execution is aborted.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:3999
validate_profiler_event_verified(
position,
expected_block_hash,
plan.pool_address,
&plan.pool,
verification,
)
.await?;
}
let ancestry = verified_value(
verification
.verify_header_window(canonical_block, head.number)
.await,
"profiler-to-decision ancestry",
)?;
if let Some(last) = ancestry.last() {
anyhow::ensure!(
*last == head,
"Swap decision header conflicts with profiler ancestry"
);
} else {
anyhow::ensure!(
canonical_block == head,
"Empty profiler ancestry does not end at the decision header"
);
}
verified_value(
verification
.verify_deployment_manifest(manifest, head.number)
.await,
"swap deployment manifest",
)?;
let quote_contract = validate_manifest_pool(plan, manifest)?;
let quote_kind = match plan.order.order_side() {
OrderSide::Sell => SwapQuoteKind::ExactInput(quantity_to_raw_amount(View on GitHub (pinned to 18893faf8b)
Solutions
- Retry execution after the reorg settles; the window is re-verified each attempt.
- Pin RPC/verification traffic to a single consistent endpoint instead of load-balanced forks.
- Refresh the profiler watermark and re-derive both the canonical block and head.
- Increase confirmation depth (max_age_blocks / head lag) so decisions are not made near reorg-prone tips.
Defensive patterns
Strategy: retry
Validate before calling
let ancestry = verification.verify_header_window(canonical_block, head.number).await?;
if let Some(last) = ancestry.last() {
if *last != head {
anyhow::bail!("decision head not on verified ancestry; reorg in progress");
}
} Try / catch
match build_quote_anchors(...).await {
Ok(a) => execute(a),
Err(e) if e.to_string().contains("conflicts with profiler ancestry") => {
tokio::time::sleep(backoff).await; // let the reorg settle
retry();
}
Err(e) => return Err(e),
} Prevention
- Use one dedicated RPC endpoint for all verification calls to avoid fork skew.
- Add short retry with backoff around ancestry verification.
- Pause trading during detected reorg windows.
When it happens
Trigger: During swap quote validation, verify_header_window(canonical_block, head.number) returns a non-empty ancestry whose last element != head — i.e. the chain reorganized between the ancestry fetch and the head fetch, or two verification calls hit different forks.
Common situations: Active reorgs on the target chain during execution; load-balanced RPC endpoints serving different forks; verifier cache out of sync; attempting execution during unstable network conditions right after a chain reorganization event.
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
- Decision header changed before signing
- Durable finalized header tip conflicts with independent sour
- Pool state block {} changed from {} to {}; refresh the profi
- Verified inclusion header does not match the finalized recei
- Verified finalized header conflicts with its ancestry window
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e21368101c81b7ba.
Report an issue: GitHub.