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

  1. Check that the start block and the follow-up window do not overlap (window should start at start+1)
  2. Verify the provider is trusted and returns canonical history; cross-check one block's transactions against a second source
  3. Clear the replacement cursor and rescan from intent.created_block
  4. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/6003bb5bc5628a9e. Report an issue: GitHub.