nautechsystems/nautilus_trader · error
Pool state block {} changed from {} to {}; refresh the profi
Error message
Pool state block {} changed from {} to {}; refresh the profiler before execution What it means
The library verifies the profiler snapshot's block hash against the canonical chain header fetched via the verification coordinator. If the canonical block at that height hashes differently, the chain reorganized (or the profiler data is wrong) between ingestion and swap decision, so execution aborts and asks for a profiler refresh. This prevents trading on quotes anchored to orphaned blocks.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:3957
let block_hash = position.block_hash.as_deref().ok_or_else(|| {
anyhow::anyhow!(
"Pool state at block {} has no ingestion-time block hash; refresh the profiler before execution",
position.number
)
})?;
let expected_block_hash = B256::from_str(block_hash)
.with_context(|| format!("Invalid profiler block hash {block_hash}"))?;
let now_unix_secs = current_unix_secs()?;
let head = verified_value(
verification.verify_decision_header(now_unix_secs).await,
"swap decision header",
)?;
validate_quote_age(position.number, head.number, max_age_blocks)?;
let canonical_block = verified_value(
verification.verify_block(position.number).await,
"profiler watermark header",
)?;
anyhow::ensure!(
canonical_block.hash == expected_block_hash,
"Pool state block {} changed from {} to {}; refresh the profiler before execution",
position.number,
expected_block_hash,
canonical_block.hash
);
let snapshot_transaction = position.transaction_index == BLOCK_SCOPED_SNAPSHOT_INDEX;
let snapshot_log = position.log_index == BLOCK_SCOPED_SNAPSHOT_INDEX;
anyhow::ensure!(
snapshot_transaction == snapshot_log,
"Pool state at block {} has an invalid partial snapshot watermark",
position.number
);
if snapshot_transaction {
let snapshot_hash = B256::from_str(&position.transaction_hash)
.with_context(|| "Invalid block-scoped snapshot hash")?;View on GitHub (pinned to 18893faf8b)
Solutions
- Refresh the profiler so pool-state snapshots are re-ingested against the current canonical chain.
- Verify the RPC endpoint and chain id match the deployment manifest (no fork/devnet/mainnet mix-up).
- Wait for the reorg to settle and retry execution once the profiler watermark is updated.
- Compare expected vs canonical hashes from the message to confirm whether it's a reorg or data corruption.
Defensive patterns
Strategy: retry
Validate before calling
let canonical = verification.verify_block(position.number).await?;
if canonical.hash != expected_block_hash {
// abort this attempt; refresh the profiler before retrying
anyhow::bail!("block {} reorganized at execution time", position.number);
} Try / catch
match build_quote_anchors(...).await {
Ok(anchors) => execute(anchors),
Err(e) if e.to_string().contains("changed from") => {
refresh_profiler().await?; // reorg or stale data
retry_with_backoff();
}
Err(e) => return Err(e),
} Prevention
- Pin execution and verification to a single consistent RPC endpoint/chain id.
- Refresh the profiler shortly before execution so watermarks are near head.
- Track reorg events and pause execution while they are in progress.
When it happens
Trigger: During swap quote-anchor validation, verification.verify_block(position.number) returns a block whose hash differs from the profiler snapshot's expected_block_hash for the same block number.
Common situations: A chain reorg after the profiler ingested the block; profiler pointed at a different network/fork (e.g. devnet vs mainnet RPC mix-up); stale profiler data after an intentional chain reset; wrong chain id in deployment manifest.
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
- Swap decision header conflicts with profiler ancestry
- 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/2d0bdbbe9d46f55e.
Report an issue: GitHub.