{"record":{"id":"27beb18b053c473c","repo":"nautechsystems/nautilus_trader","slug":"canonical-nonce-is-outside-the-owned-reconcilia","errorCode":null,"errorMessage":"Canonical nonce {} is outside the owned reconciliation range {}..={next_nonce}","messagePattern":"Canonical nonce (.+?) is outside the owned reconciliation range (.+?)\\.\\.=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":2922,"sourceCode":"        let receipt_absence = required_verification(\n            self.verification\n                .verify_receipt_absence(&prepared.tx_hash)\n                .await,\n            \"rebroadcast receipt absence\",\n        )?;\n        decisions.push(verification_decision(&receipt_absence, None, None));\n\n        let next_nonce = prepared\n            .nonce\n            .checked_add(1)\n            .ok_or_else(|| anyhow::anyhow!(\"Owned signer nonce overflow\"))?;\n        anyhow::ensure!(\n            (prepared.nonce..=next_nonce).contains(&pending_nonce.value),\n            \"Pending nonce {} is outside the owned reconciliation range {}..={next_nonce}\",\n            pending_nonce.value,\n            prepared.nonce\n        );\n        anyhow::ensure!(\n            (prepared.nonce..=next_nonce).contains(&canonical_nonce.value),\n            \"Canonical nonce {} is outside the owned reconciliation range {}..={next_nonce}\",\n            canonical_nonce.value,\n            prepared.nonce\n        );\n\n        if !receipt_absence.value {\n            self.persist_rebroadcast_decisions(intent.id, prepared.nonce, &decisions)\n                .await?;\n            return Ok(ReconciliationAuthorization::Retain);\n        }\n\n        if canonical_nonce.value == next_nonce {\n            self.persist_rebroadcast_decisions(intent.id, prepared.nonce, &decisions)\n                .await?;\n            return Ok(ReconciliationAuthorization::ScanReplacement(\n                decision_header.value,\n            ));","sourceCodeStart":2904,"sourceCodeEnd":2940,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L2904-L2940","documentation":"During rebroadcast reconciliation, the execution client re-fetches the wallet's canonical (mined) transaction count and the pending transaction count, and ensures both fall within the nonce range owned by the prepared transaction (prepared.nonce..=prepared.nonce+1). If the chain reports a canonical nonce outside this tiny window, the wallet's on-chain state has diverged from the client's local in-flight transaction, so it refuses to authorize the rebroadcast rather than broadcast a duplicate or stale transaction.","triggerScenarios":"authorize_rebroadcast() was called for a PreparedTransaction whose nonce no longer matches the chain's transaction_count for the wallet: e.g. another process/wallet instance already broadcast and mined a transaction with a different nonce, the local nonce bookkeeping drifted, or a replacement transaction with an unrelated nonce was mined in between.","commonSituations":"Running two executors against the same wallet key; manual transactions sent from the wallet out-of-band; restarting the client after nonce state was lost; an RPC endpoint behind a load balancer returning inconsistent nonces; replaying intents prepared against a different chain state.","solutions":["Stop all other senders using this wallet so this client is the sole nonce owner","Check the reported canonical nonce: if it equals prepared.nonce+1 the transaction was mined — let reconciliation retain rather than rebroadcast","Reset the client's local nonce from the chain's latest transaction count and re-prepare the transaction","Verify the RPC endpoint targets the intended chain_id and a consistent node"],"exampleFix":"// before\nlet prepared = client.prepare_transaction(intent); // stale local nonce\n// after\nlet onchain_nonce = client.transaction_count(wallet).await;\nlet prepared = client.prepare_transaction_with_nonce(intent, onchain_nonce);","handlingStrategy":"validation","validationCode":"let canonical = client.transaction_count(wallet).await?;\nlet pending = client.pending_count(wallet).await?;\nlet next = prepared.nonce.checked_add(1).expect(\"nonce overflow\");\nif !(prepared.nonce..=next).contains(&canonical) || !(prepared.nonce..=next).contains(&pending) {\n    return Err(\"nonce window mismatch; resync local nonce from chain\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use a single nonce owner per wallet key","Refresh local nonce from the chain before preparing transactions","Pin to one consistent RPC endpoint","Track and persist in-flight nonces across restarts"],"tags":["blockchain","nonce","ethereum","reconciliation"],"backgroundTag":"invalid-state-transition","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}