{"record":{"id":"f21f2385dd66bb99","repo":"nautechsystems/nautilus_trader","slug":"verified-finality-manifest-identity-changed","errorCode":null,"errorMessage":"Verified finality manifest identity changed","messagePattern":"Verified finality manifest identity changed","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":6948,"sourceCode":"            self.pool.begin().await.map_err(|e| {\n                anyhow::anyhow!(\"Failed to start verified finality transition: {e}\")\n            })?;\n        let (manifest_version, manifest_digest, stored_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(finality.wallet_address)\n            .fetch_optional(&mut *transaction)\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to lock finality nonce ledger: {e}\"))?\n            .ok_or_else(|| anyhow::anyhow!(\"Canonical nonce ledger is not initialized\"))?;\n        anyhow::ensure!(\n            manifest_version == finality.manifest_version\n                && manifest_digest == finality.manifest_digest,\n            \"Verified finality manifest identity changed\"\n        );\n        anyhow::ensure!(\n            stored_nonce == nonce,\n            \"Finalized nonce {} does not match canonical nonce {stored_nonce}\",\n            finality.nonce\n        );\n        let stored_tip = 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        )","sourceCodeStart":6930,"sourceCodeEnd":6966,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L6930-L6966","documentation":"Thrown by `record_execution_finality_verified` after locking the canonical nonce ledger row. The function compares the stored (manifest_version, manifest_digest) in the execution_verification_nonce table against the manifest identity carried by the incoming ExecutionFinalityTransition; if either differs, this ensure! fires. It is an integrity guard ensuring finality evidence is only persisted against the same verified manifest the ledger was created with.","triggerScenarios":"Calling record_execution_finality_verified when finality.manifest_version or finality.manifest_digest differs from the values stored for that (chain_id, wallet_address). Typical: the execution manifest was regenerated or edited after the ledger was created, a different build/version of the manifest was verified, or the digest computation changed between library versions.","commonSituations":"Upgrading the adapter/manifest format while reusing an old database; editing the execution manifest (changing intents or ordering) so its digest no longer matches; running two processes with different manifest versions against the same database; replaying historical finality data recorded under an older manifest digest.","solutions":["Re-verify the execution manifest so the ledger's manifest_version and manifest_digest are updated to the current identity before recording finality","Ensure the exact same manifest bytes that produced the stored digest are being verified; recompute the digest and compare before calling record_execution_finality_verified","If the manifest intentionally changed, re-initialize/rebuild the verification state for this chain/wallet from scratch under the new manifest","Check for a library version mismatch: pin all processes writing to the database to the same adapter version and manifest format"],"exampleFix":"// before: finality transition built from a stale/edited manifest\nlet finality = build_finality(&edited_manifest, ...);\ncache.record_execution_finality_verified(&finality).await?; // digest mismatch\n\n// after: assert identity matches before persisting\nassert_eq!(manifest.digest().to_string(), stored_digest);\nlet finality = build_finality(&verified_manifest, ...);\ncache.record_execution_finality_verified(&finality).await?;","handlingStrategy":"validation","validationCode":"let (version, digest): (String, String) = sqlx::query_as(\n    \"SELECT manifest_version, manifest_digest FROM execution_verification_nonce WHERE chain_id = $1 AND wallet_address = $2\"\n)\n.bind(chain_id).bind(wallet_address).fetch_one(&pool).await?;\nanyhow::ensure!(\n    version == manifest.version && digest == manifest.digest().to_string(),\n    \"Manifest identity drifted; re-verify before recording finality\"\n);","typeGuard":null,"tryCatchPattern":"match cache.record_execution_finality_verified(&finality).await {\n    Err(e) if e.to_string().contains(\"manifest identity changed\") => {\n        // halt and re-verify the manifest; do not blindly retry\n    }\n    result => result?,\n}","preventionTips":["Treat the manifest digest as immutable content addressing: any manifest edit requires a full re-verification pass","Pin the adapter and manifest format version across all writers sharing one database","Log and compare manifest digests at startup to detect drift before any finality recording"],"tags":["database","integrity-check","blockchain","rust"],"backgroundTag":"checksum-mismatch","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"}