nautechsystems/nautilus_trader · error
Canonical nonce advanced without an authenticated signer tra
Error message
Canonical nonce advanced without an authenticated signer transaction in the scanned canonical range
What it means
scan_canonical_replacement() computes a scan start block (from a persisted replacement cursor or the intent's creation block) and requires that start be at or before the current canonical head. If the computed start is past the head, the canonical nonce advanced without any authenticated signer transaction being found in the scanned canonical range — an internal consistency violation meaning the ledger and chain state disagree.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:3054
nonce: u64,
head: VerifiedBlockHeader,
authenticated_payloads: &HashMap<B256, Vec<u8>>,
) -> anyhow::Result<Option<(B256, Vec<u8>)>> {
let wallet_address = self.wallet_address.to_string();
let cursor = self
.database
.load_execution_replacement_cursor(
intent.id,
self.chain_id,
&wallet_address,
nonce,
&self.manifest_digest,
)
.await?;
let start = cursor.as_ref().map_or(intent.created_block, |header| {
header.number.saturating_add(1)
});
anyhow::ensure!(
start <= head.number,
"Canonical nonce advanced without an authenticated signer transaction in the scanned canonical range"
);
let scan_range = replacement_scan_range(start, head.number)?;
let end = *scan_range.end();
let mut decisions = Vec::new();
let mut blocks = Vec::new();
if let Some(cursor) = cursor.as_ref() {
let parent = parse_verified_header(cursor)?;
let window = required_verification(
self.verification
.verify_replacement_window(parent, end)
.await,
"canonical replacement window",
)?;
decisions.push(verification_decision(&window, Some(start), Some(end)));
blocks = window.value;View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the RPC endpoint is fully synced (head block number matches network consensus)
- Check the replacement cursor row in the database for the intent and correct or clear it so the scan restarts from intent.created_block
- Confirm chain_id and network settings match the chain the intent was created on
- If a reorg occurred, re-run reconciliation after the chain stabilizes
Example fix
// before let head = provider.get_block_number().await?; // lagging replica // after let head = provider.get_block_number().await; ensure!(head >= cursor_block, "RPC head lagging; retry with a synced node");
Defensive patterns
Strategy: validation
Validate before calling
let head = client.head_block_number().await?;
let start = cursor.map_or(intent.created_block, |h| h.number.saturating_add(1));
if start > head {
return Err("scan start exceeds head; check RPC sync and cursor");
} Try / catch
match result {
Err(e) if e.to_string().contains("authenticated signer transaction") => resync_cursor_and_retry(),
other => other,
} Prevention
- Monitor RPC head lag before reconciliation
- Validate persisted cursors against the chain on startup
- Use a single trusted node for head queries
- Detect and handle reorgs before scanning
When it happens
Trigger: The durable replacement cursor (or intent.created_block) points to a block number greater than the current verified head: e.g. querying a lagging/replica RPC node, a reorg rewound the head, or a corrupted cursor row was loaded from the database.
Common situations: RPC provider failover to a lagging node; database cursor persisted against a different chain or manifest; deep chain reorg after the intent was created; clock/seed misconfiguration pointing at a testnet.
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.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Replacement scan cursor conflicts with the finalized header
- Persisted terminal transaction {tx_hash} is not stable at th
- Replacement block conflicts with its canonical header
- Replacement scan tip conflicts with the verified canonical h
- Profiler receipt position does not match its ingestion water
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c5ead93a92556658.
Report an issue: GitHub.