nautechsystems/nautilus_trader · error
Canonical head {head_block} is behind execution creation blo
Error message
Canonical head {head_block} is behind execution creation block {from_block} What it means
`replacement_scan_range` computes the block range to scan for a replacement transaction and requires the current canonical head to be at or beyond the original creation block. A head behind `from_block` means the chain view regressed relative to the execution's own history (fork/reorg or connected to a stale/different node), so no valid scan range exists.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:3574
effective_gas_price: &effective_gas_price,
manifest_version: &self.manifest_version,
manifest_digest: &self.manifest_digest,
provider_ids: &self.provider_ids,
operator_ids: &self.operator_ids,
failure_domain_ids: &self.failure_domain_ids,
decisions: &decisions,
finalized_headers: &included.finality.finalized_headers,
})
.await
}
fn release_slot(&self) {
*self.in_flight.lock() = None;
}
}
fn replacement_scan_range(from_block: u64, head_block: u64) -> anyhow::Result<RangeInclusive<u64>> {
anyhow::ensure!(
head_block >= from_block,
"Canonical head {head_block} is behind execution creation block {from_block}"
);
let max_end = from_block.saturating_add(MAX_REPLACEMENT_SCAN_BLOCKS - 1);
Ok(from_block..=head_block.min(max_end))
}
fn current_unix_secs() -> anyhow::Result<u64> {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|_| anyhow::anyhow!("Trusted host clock precedes the Unix epoch"))
.map(|duration| duration.as_secs())
}
fn validate_payload_operation_batch_size(batch_size: usize) -> anyhow::Result<i64> {
anyhow::ensure!(
(1..=MAX_PAYLOAD_OPERATION_BATCH_SIZE).contains(&batch_size),
"Payload operation batch size must be between 1 and {MAX_PAYLOAD_OPERATION_BATCH_SIZE}"View on GitHub (pinned to 18893faf8b)
Solutions
- Check the connected node's sync status and chain ID; wait for it to reach at least `from_block`.
- Re-point the client at the previously used healthy RPC endpoint.
- Recompute `from_block` from current canonical chain data.
Example fix
// before: failover to lagging node let head = lagging_provider.block_number().await?; // 800 replacement_scan_range(1000, head)?; // ensure! fails // after: guard before scanning ensure!(head >= from_block, "waiting for node sync");
Defensive patterns
Strategy: validation
Validate before calling
let head = provider.block_number().await?;
anyhow::ensure!(head >= from_block, "node head {} behind creation block {}", head, from_block); Try / catch
match replacement_scan_range(from_block, head) {
Err(e) if e.to_string().contains("behind execution creation block") => wait_for_sync_then_retry().await,
other => other,
} Prevention
- Check node sync state after any RPC failover
- Verify chain ID matches the previous endpoint
- Compute from_block from canonical chain data, not local clocks
When it happens
Trigger: Requesting a replacement (speed-up/cancel) scan when `head_block < from_block` — e.g. after switching to a lagging RPC node, or a reorg that rolled the head below the block where the original transaction was created.
Common situations: Failover to an unsynced RPC endpoint; connecting to a different network with lower block height; misconfigured `from_block` computed from a wrong clock or chain data.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Finalized block {} does not contain transaction {}
- Profiler receipt position does not match its ingestion water
- Invalid execution transition for intent {intent_id}: {curren
- Finalized execution transaction {tx_hash} no longer has a re
- Canonical head changed during signer-nonce replacement scan
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/bc29ea27f758bbea.
Report an issue: GitHub.