{"record":{"id":"e47acb83c7ebc298","repo":"nautechsystems/nautilus_trader","slug":"canonical-nonce-ledger-is-not-initialized","errorCode":null,"errorMessage":"Canonical nonce ledger is not initialized","messagePattern":"Canonical nonce ledger is not initialized","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":5927,"sourceCode":"            .pool\n            .begin()\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to start verified nonce assignment: {e}\"))?;\n        let (manifest_version, manifest_digest, next_nonce, revision) =\n            sqlx::query_as::<_, (String, String, i64, i64)>(\n                \"\n                SELECT manifest_version, manifest_digest, next_canonical_nonce, revision\n                FROM execution_verification_nonce\n                WHERE chain_id = $1 AND wallet_address = $2\n                FOR UPDATE\n                \",\n            )\n            .bind(chain_id)\n            .bind(assignment.wallet_address)\n            .fetch_optional(&mut *transaction)\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to lock canonical nonce ledger: {e}\"))?\n            .ok_or_else(|| anyhow::anyhow!(\"Canonical nonce ledger is not initialized\"))?;\n        anyhow::ensure!(\n            manifest_version == assignment.manifest_version\n                && manifest_digest == assignment.manifest_digest,\n            \"Verified nonce assignment manifest identity changed\"\n        );\n        anyhow::ensure!(\n            next_nonce == nonce,\n            \"Execution nonce {} does not match canonical nonce {next_nonce}\",\n            assignment.nonce\n        );\n\n        let (intent_chain_id, intent_wallet, intent_nonce, intent_status, intent_active) =\n            sqlx::query_as::<_, (i32, String, Option<i64>, String, bool)>(\n                \"\n            SELECT chain_id, wallet_address, nonce, status, active\n            FROM execution_intent\n            WHERE id = $1\n            FOR UPDATE","sourceCodeStart":5909,"sourceCodeEnd":5945,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L5909-L5945","documentation":"The transaction tried to lock the canonical nonce ledger row for (chain_id, wallet_address) but the SELECT returned no rows. The ledger must be pre-initialized (a row must exist) before any verified nonce assignment can proceed. This is an explicit guard against assigning nonces when the on-disk canonical state is absent.","triggerScenarios":"Calling the verified nonce assignment API for a chain/wallet pair whose `execution_verification_nonce` row has never been created by the initialization routine — e.g. a new wallet added without running ledger init, or a chain_id/address encoding mismatch so the WHERE clause misses the existing row.","commonSituations":"Deploying a new chain/wallet configuration without running the ledger bootstrap; environment pointing at a fresh empty database; chain_id or wallet_address case/encoding mismatch (e.g. EIP-55 checksum vs lowercase); manifest regenerated with a new wallet.","solutions":["Run the ledger initialization/bootstrap step for this (chain_id, wallet_address) before assigning nonces.","Verify the chain_id and wallet_address passed in the assignment exactly match the initialized row (check case and encoding of the address).","Confirm you are connected to the intended database — a fresh/empty DB will not have the row.","Query `SELECT * FROM execution_verification_nonce WHERE chain_id=$1` to see which wallets are initialized.","If the row was deleted, restore it via the manifest bootstrap process rather than inserting ad hoc."],"exampleFix":"// before\n db.assign_verified_nonce(assignment).await?;\n// after\n db.initialize_nonce_ledger(chain_id, wallet, manifest).await?; // ensure row exists first\n db.assign_verified_nonce(assignment).await?;","handlingStrategy":"validation","validationCode":"async fn ledger_initialized(pool: &PgPool, chain_id: i64, wallet: &str) -> anyhow::Result<bool> {\n    Ok(sqlx::query(\"SELECT 1 FROM execution_verification_nonce WHERE chain_id = $1 AND wallet_address = $2\").bind(chain_id).bind(wallet).fetch_optional(pool).await?.is_some())\n}","typeGuard":"fn is_ledger_missing(err: &anyhow::Error) -> bool {\n    err.to_string().contains(\"Canonical nonce ledger is not initialized\")\n}","tryCatchPattern":"match db.assign_verified_nonce(&assignment).await {\n    Err(e) if is_ledger_missing(&e) => {\n        db.initialize_nonce_ledger(chain_id, wallet, manifest).await?;\n        db.assign_verified_nonce(&assignment).await\n    }\n    other => other,\n}","preventionTips":["Run ledger initialization for every (chain_id, wallet) in the manifest at service startup.","Normalize wallet addresses (e.g. lowercase) consistently before all DB reads/writes.","Validate chain_id configuration against initialized rows before accepting assignments.","Watch for fresh/empty databases when promoting environments.","Alert on 'ledger not initialized' occurrences — they usually indicate config or bootstrap drift."],"tags":["database","postgres","missing-row","initialization"],"backgroundTag":"record-not-found","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}