nautechsystems/nautilus_trader · error · anyhow::Error
Canonical nonce ledger is not initialized
Error message
Canonical nonce ledger is not initialized
What it means
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.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:5927
.pool
.begin()
.await
.map_err(|e| anyhow::anyhow!("Failed to start verified nonce assignment: {e}"))?;
let (manifest_version, manifest_digest, next_nonce, revision) =
sqlx::query_as::<_, (String, String, i64, i64)>(
"
SELECT manifest_version, manifest_digest, next_canonical_nonce, revision
FROM execution_verification_nonce
WHERE chain_id = $1 AND wallet_address = $2
FOR UPDATE
",
)
.bind(chain_id)
.bind(assignment.wallet_address)
.fetch_optional(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to lock canonical nonce ledger: {e}"))?
.ok_or_else(|| anyhow::anyhow!("Canonical nonce ledger is not initialized"))?;
anyhow::ensure!(
manifest_version == assignment.manifest_version
&& manifest_digest == assignment.manifest_digest,
"Verified nonce assignment manifest identity changed"
);
anyhow::ensure!(
next_nonce == nonce,
"Execution nonce {} does not match canonical nonce {next_nonce}",
assignment.nonce
);
let (intent_chain_id, intent_wallet, intent_nonce, intent_status, intent_active) =
sqlx::query_as::<_, (i32, String, Option<i64>, String, bool)>(
"
SELECT chain_id, wallet_address, nonce, status, active
FROM execution_intent
WHERE id = $1
FOR UPDATEView on GitHub (pinned to 18893faf8b)
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.
Example fix
// before db.assign_verified_nonce(assignment).await?; // after db.initialize_nonce_ledger(chain_id, wallet, manifest).await?; // ensure row exists first db.assign_verified_nonce(assignment).await?;
Defensive patterns
Strategy: validation
Validate before calling
async fn ledger_initialized(pool: &PgPool, chain_id: i64, wallet: &str) -> anyhow::Result<bool> {
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())
} Type guard
fn is_ledger_missing(err: &anyhow::Error) -> bool {
err.to_string().contains("Canonical nonce ledger is not initialized")
} Try / catch
match db.assign_verified_nonce(&assignment).await {
Err(e) if is_ledger_missing(&e) => {
db.initialize_nonce_ledger(chain_id, wallet, manifest).await?;
db.assign_verified_nonce(&assignment).await
}
other => other,
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Database is not initialized, so we cannot properly bootstrap
- Could not calculate schema dir from current directory path o
- Error executing statement {sql_statement} with error: {e:?}
- Error dropping role {database}: {e:?}
- Failed to load order events: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e47acb83c7ebc298.
Report an issue: GitHub.