{"record":{"id":"4cdf5f396f03f521","repo":"nautechsystems/nautilus_trader","slug":"finalized-header-manifest-identity-changed","errorCode":null,"errorMessage":"Finalized header manifest identity changed","messagePattern":"Finalized header manifest identity changed","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":3732,"sourceCode":"            \"Execution verification manifest identity changed\"\n        );\n        let row = sqlx::query_as::<_, (i64, String, String, i64, Option<String>, String)>(\n            \"\n            SELECT number, hash, parent_hash, timestamp, base_fee_per_gas, manifest_digest\n            FROM execution_verified_finalized_header\n            WHERE chain_id = $1 AND wallet_address = $2\n            ORDER BY number DESC\n            LIMIT 1\n            \",\n        )\n        .bind(chain_id)\n        .bind(wallet_address)\n        .fetch_optional(&self.pool)\n        .await\n        .context(\"failed to load verified finalized header tip\")?\n        .ok_or_else(|| anyhow::anyhow!(\"Verified finalized header ledger is empty\"))?;\n        let (number, hash, parent_hash, timestamp, base_fee, digest) = row;\n        anyhow::ensure!(\n            digest == manifest_digest,\n            \"Finalized header manifest identity changed\"\n        );\n        Ok(Some(ExecutionVerificationPosition {\n            next_canonical_nonce: u64::try_from(nonce).context(\"Canonical nonce is negative\")?,\n            revision: u64::try_from(revision).context(\"Canonical nonce revision is negative\")?,\n            finalized_tip: ExecutionVerifiedHeader {\n                number: u64::try_from(number).context(\"Finalized header number is negative\")?,\n                hash,\n                parent_hash,\n                timestamp: u64::try_from(timestamp)\n                    .context(\"Finalized header timestamp is negative\")?,\n                base_fee_per_gas: base_fee\n                    .map(|value| {\n                        value\n                            .parse::<u128>()\n                            .map_err(|_| anyhow::anyhow!(\"Finalized header base fee is invalid\"))\n                    })","sourceCodeStart":3714,"sourceCodeEnd":3750,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L3714-L3750","documentation":"Raised in database.rs:3732 when the manifest_digest stored on the latest verified finalized header row does not equal the caller's manifest_digest. The tip header was recorded under a different verification manifest, so its data cannot be trusted as a continuation point for the current manifest's verification.","triggerScenarios":"Loading the verified finalized header tip in load_execution_verification_position when the digest column of the newest execution_verified_finalized_header row differs from the manifest_digest parameter passed by the caller.","commonSituations":"Verification manifest changed (contract set or rules updated) after headers were already recorded; restoring a mixed database where headers came from a different deployment; passing the wrong manifest digest in code/config.","solutions":["Re-bootstrap verification state under the current manifest so headers are re-recorded with the active digest.","Ensure the manifest_digest passed to load_execution_verification_position is identical to the one used when headers were written.","Revert the manifest configuration change if it was unintended (compare digests against the stored rows).","Do not delete or rewrite the digest column manually; rotate state through the bootstrap path instead."],"exampleFix":"// before: digest mismatch on tip header\nlet pos = db.load_execution_verification_position(chain, wallet, ver, &new_digest).await?;\n// Err: Finalized header manifest identity changed\n\n// after: use the digest under which the ledger was written, or re-bootstrap under new_digest\nlet pos = db.load_execution_verification_position(chain, wallet, ver, &ledger_digest).await?;","handlingStrategy":"validation","validationCode":"let tip: Option<String> = sqlx::query_scalar(\n    \"SELECT manifest_digest FROM execution_verified_finalized_header \\\n     WHERE chain_id = $1 AND wallet_address = $2 ORDER BY number DESC LIMIT 1\",\n).bind(chain_id).bind(wallet).fetch_optional(&pool).await?;\nif tip.as_deref() != Some(manifest_digest) {\n    anyhow::bail!(\"ledger digest {:?} != active manifest digest\", tip);\n}","typeGuard":null,"tryCatchPattern":"match load_position(...).await {\n    Err(e) if e.to_string().contains(\"Finalized header manifest identity changed\") => {\n        // stop; re-bootstrap or revert manifest config before continuing\n    },\n    other => other?,\n}","preventionTips":["Keep manifest digest in config under change control","Re-bootstrap whenever the manifest digest changes","Diff active config digest against the stored ledger digest at startup"],"tags":["database","integrity","verification","manifest"],"backgroundTag":"checksum-mismatch","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"}