{"record":{"id":"519b0d965f9f9e15","repo":"nautechsystems/nautilus_trader","slug":"retained-active-nonce-nonce-is-above-canonical-n","errorCode":null,"errorMessage":"Retained active nonce {nonce} is above canonical nonce {next_canonical_nonce}","messagePattern":"Retained active nonce (.+?) is above canonical nonce (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":5486,"sourceCode":"                    !matches!(intent.status.as_str(), \"finalized\" | \"reverted\"),\n                    \"Active terminal intent conflicts with the canonical nonce ledger\"\n                );\n                records.push(ExecutionVerificationMigrationRecord {\n                    intent_id: intent.id,\n                    nonce: Some(nonce),\n                    transaction_hash: Some(current.transaction_hash.clone()),\n                    terminal_status: None,\n                    block_number: None,\n                    block_hash: None,\n                    receipt_success: None,\n                    gas_used: None,\n                    effective_gas_price: None,\n                    recover_prepared: false,\n                    decisions: vec![base_decision],\n                });\n                continue;\n            }\n            anyhow::ensure!(\n                nonce < next_canonical_nonce,\n                \"Retained active nonce {nonce} is above canonical nonce {next_canonical_nonce}\"\n            );\n\n            let receipt_verification = required_verification(\n                self.verification\n                    .verify_receipt(&B256::from_str(&current.transaction_hash).with_context(\n                        || {\n                            format!(\n                                \"Retained transaction hash {} is invalid\",\n                                current.transaction_hash\n                            )\n                        },\n                    )?)\n                    .await,\n                \"migration receipt\",\n            )?;\n            let receipt = receipt_verification.value.clone();","sourceCodeStart":5468,"sourceCodeEnd":5504,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L5468-L5504","documentation":"During migration, an active signed intent whose nonce is not the next canonical nonce must lie strictly below it (an in-flight older transaction). This error is thrown when a retained active intent's nonce is greater than or equal to the canonical next nonce, meaning the signer's persisted ledger thinks a transaction occupies a nonce at or beyond what the account has not yet used — a ledger/account-state divergence that would cause nonce reuse or gaps. The library fails the migration rather than broadcasting with a conflicting nonce.","triggerScenarios":"Raised by `anyhow::ensure!(nonce < next_canonical_nonce, ...)` when: the on-chain account nonce advanced past what the local ledger recorded (e.g. transactions signed/managed outside this client, or the node reconnected to a different signer account), or the local canonical nonce was recomputed downward after a state restore while active intents retained higher nonces.","commonSituations":"Using the same signing key from another process/wallet concurrently; restoring an old local state while the chain account moved on; pointing the adapter at a different RPC endpoint/account than the one whose state was persisted; missed reorg handling that rolled back the canonical nonce incorrectly.","solutions":["Query the account's current nonce from the RPC and reconcile the local canonical nonce ledger to it before re-running migration.","Ensure no other wallet/process signs with the same key; move to a dedicated signer key for this client.","For intents with nonces above the account nonce, cancel or re-prepare them (drop/recover) so their stale nonces no longer count as active.","Confirm the configured account/address matches the one used when the state was persisted; fix the config and rebuild the ledger."],"exampleFix":"// before (stale local canonical nonce after external transactions)\nlet next_canonical_nonce = persisted_ledger.next_nonce;  // 5\n// retained active intent nonce = 7 -> error\n\n// after (resync from chain before migrating)\nlet next_canonical_nonce = provider.get_transaction_count(address, None).await?;  // 8\ndrop_or_recover_intents_above(next_canonical_nonce);","handlingStrategy":"validation","validationCode":"async fn check_nonce_health(provider: &Provider, address: Address, ledger_next: u64, active_intents: &[Intent]) -> Result<(), String> {\n    let chain_nonce = provider.get_transaction_count(address, None).await?;\n    if ledger_next < chain_nonce {\n        return Err(format!(\"local canonical nonce {} below chain nonce {}\", ledger_next, chain_nonce));\n    }\n    if active_intents.iter().any(|i| i.nonce.map_or(false, |n| n >= ledger_next && n != ledger_next)) {\n        return Err(\"active intent nonce above canonical nonce\".into());\n    }\n    Ok(())\n}","typeGuard":"fn nonce_in_range(intent: &Intent, next_canonical: u64) -> bool {\n    intent.nonce.map_or(true, |n| n < next_canonical)\n}","tryCatchPattern":null,"preventionTips":["Never sign with the same key from multiple processes or wallets.","Resync the canonical nonce from the chain before every migration/startup.","Confirm the configured signer address matches the account the state was built for.","Handle reorgs by re-deriving the canonical nonce rather than decrementing persisted values.","Cancel or drop stale intents whose nonces exceed the account nonce."],"tags":["blockchain","nonce","ledger-divergence","state-migration"],"backgroundTag":"invalid-argument-value","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"}