nautechsystems/nautilus_trader · error
Canonical replacement scan found duplicate signer-nonce tran
Error message
Canonical replacement scan found duplicate signer-nonce transactions
What it means
While scanning canonical blocks for a transaction with the wallet's signer nonce, the client expects at most one transaction matching (from == wallet, nonce == N). Finding two or more means the scanned history contains duplicate signer-nonce transactions, which is impossible on a valid canonical chain and indicates corrupted or cross-branch data.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:3127
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
.database
.load_execution_verified_header(
self.chain_id,
&wallet_address,
end,
&self.manifest_digest,
)
.await?;
if let Some(cursor) = finalized_cursor.as_ref() {
anyhow::ensure!(
parse_verified_header(cursor)? == scanned_tip,
"Replacement scan conflicts with the durable finalized header ledger"View on GitHub (pinned to 18893faf8b)
Solutions
- Check that the start block and the follow-up window do not overlap (window should start at start+1)
- Verify the provider is trusted and returns canonical history; cross-check one block's transactions against a second source
- Clear the replacement cursor and rescan from intent.created_block
- Audit the manifest_digest/chain configuration for mixing environments
Defensive patterns
Strategy: validation
Validate before calling
let mut matches = blocks.iter()
.flat_map(|b| b.transactions.iter())
.filter(|tx| tx.from == wallet && tx.nonce == nonce);
let first = matches.next();
if matches.next().is_some() {
return Err("duplicate signer-nonce txs; block windows overlap or provider untrusted");
} Prevention
- Ensure scan windows are disjoint (window starts at start+1)
- Use only trusted, verified data sources
- Reset cursors to avoid overlapping rescans
- Never mix block data from multiple providers in one scan
When it happens
Trigger: The concatenated replacement-scan blocks contained multiple transactions from self.wallet_address with the same nonce — e.g. overlapping block windows concatenated twice, the cursor produced overlapping ranges, or an untrusted provider returned duplicate/malformed block payloads.
Common situations: Bug or corruption in block-window assembly (start block plus window overlapping); malicious or misconfigured RPC returning fabricated transactions; mixing data from two providers.
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.
Related errors
- Replacement hash {transaction_hash} conflicts with another i
- Canonical head changed during signer-nonce replacement scan
- Verified finalized transaction count advanced without an act
- Execution intent {} has a signed transaction {} that was not
- Canonical nonce advanced without an authenticated signer tra
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/6003bb5bc5628a9e.
Report an issue: GitHub.