nautechsystems/nautilus_trader · error · anyhow::Error

Canonical nonce overflow

Error message

Canonical nonce overflow

What it means

When the observed canonical nonce differs from the stored one, the code computes stored_nonce + 1 with checked_add; if the stored nonce is i64::MAX the increment overflows and crates/adapters/blockchain/src/cache/database.rs:4040 returns this error. It means the durable nonce ledger has reached the maximum representable value, so no further canonical nonce can be produced.

Source

Thrown at crates/adapters/blockchain/src/cache/database.rs:4040

        {
            anyhow::ensure!(
                bootstrap.migration.is_none(),
                "Verification migration was supplied for an initialized signer"
            );
            anyhow::ensure!(
                manifest_version == bootstrap.manifest_version
                    && manifest_digest == bootstrap.manifest_digest,
                "Execution verification manifest identity changed"
            );
            anyhow::ensure!(
                stored_nonce == next_canonical_nonce,
                "Canonical nonce ledger changed during verification bootstrap"
            );

            if observed_canonical_nonce != stored_nonce {
                let expected_observed_nonce = stored_nonce
                    .checked_add(1)
                    .ok_or_else(|| anyhow::anyhow!("Canonical nonce overflow"))?;
                anyhow::ensure!(
                    observed_canonical_nonce == expected_observed_nonce,
                    "Verified finalized transaction count is outside the owned recovery range"
                );
                let recovery = sqlx::query_as::<_, (Option<i64>, String, i64)>(
                    "
                    SELECT
                        intent.nonce,
                        intent.status,
                        COUNT(hash.id) FILTER (
                            WHERE hash.current
                              AND hash.payload_expected
                              AND ((hash.raw_transaction IS NOT NULL)::INTEGER
                                   + (hash.sealed_transaction IS NOT NULL)::INTEGER) = 1
                              AND hash.status IN (
                                  'broadcast', 'included', 'replaced', 'dropped', 'reorged'
                              )
                        )

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the ledger row (SELECT next_canonical_nonce FROM execution_verification_nonce ...) — a value at i64::MAX indicates corruption, since real wallets cannot send 2^63-1 transactions.
  2. Verify the wallet's actual on-chain nonce and rebuild the canonical nonce ledger from verified finalized transaction history.
  3. Audit any code paths that write next_canonical_nonce for missing bounds checks or sentinel-value misuse.
  4. Escalate as a data-integrity incident; do not hand-edit the value without reconstructing from on-chain state.
Defensive patterns

Strategy: validation

Validate before calling

let stored = sqlx::query_scalar::<_, i64>(
    "SELECT next_canonical_nonce FROM execution_verification_nonce WHERE chain_id=$1 AND wallet_address=$2",
).bind(chain_id).bind(wallet).fetch_one(&pool).await?;
if stored >= i64::MAX - 1 {
    return Err(anyhow::anyhow!("canonical nonce at i64 bound; ledger is corrupt"));
}

Try / catch

match bootstrap_verification(...).await {
    Err(e) if e.to_string().contains("Canonical nonce overflow") => {
        // halt trading for this signer; escalate as data-integrity incident, rebuild ledger from chain
    }
    other => other?,
}

Prevention

When it happens

Trigger: Bootstrapping verification where execution_verification_nonce.next_canonical_nonce == i64::MAX and the observed finalized transaction count is greater than the stored nonce, forcing the checked_add(1) overflow path.

Common situations: Corrupted or poisoned ledger row with a sentinel/max value; a bug elsewhere writing huge nonce values; an i64 counter saturated after an astronomically implausible number of transactions (practically only via data corruption).

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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