{"record":{"id":"aa85fabbd1bb796a","repo":"nautechsystems/nautilus_trader","slug":"replacement-scan-cursor-conflicts-with-the-finaliz","errorCode":null,"errorMessage":"Replacement scan cursor conflicts with the finalized header ledger","messagePattern":"Replacement scan cursor conflicts with the finalized header ledger","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":6315,"sourceCode":"                \"\n                SELECT hash\n                FROM execution_verified_finalized_header\n                WHERE chain_id = $1 AND wallet_address = $2 AND number = $3\n                \",\n            )\n            .bind(chain_id)\n            .bind(scan.wallet_address)\n            .bind(number)\n            .fetch_optional(&mut *transaction)\n            .await\n            .context(\"failed to validate replacement cursor against finalized headers\")?\n            .ok_or_else(|| {\n                anyhow::anyhow!(\n                    \"Replacement scan cursor {} is not durably finalized\",\n                    cursor.number\n                )\n            })?;\n            anyhow::ensure!(\n                durable_hash == cursor.hash,\n                \"Replacement scan cursor conflicts with the finalized header ledger\"\n            );\n            let existing = sqlx::query_as::<_, (i64, String)>(\n                \"\n                SELECT finalized_cursor_number, finalized_cursor_hash\n                FROM execution_replacement_scan\n                WHERE intent_id = $1\n                FOR UPDATE\n                \",\n            )\n            .bind(scan.intent_id)\n            .fetch_optional(&mut *transaction)\n            .await\n            .context(\"failed to lock replacement scan progress\")?;\n\n            if let Some((stored_number, stored_hash)) = existing {\n                anyhow::ensure!(","sourceCodeStart":6297,"sourceCodeEnd":6333,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L6297-L6333","documentation":"After finding the durable header for the cursor's block number, the code compares the stored hash with `cursor.hash` under `anyhow::ensure!`. A mismatch means the cursor claims a hash that contradicts the verified finalized header ledger — i.e. the local view of that block diverges from what was durably verified (or the cursor is corrupt/forged).","triggerScenarios":"Calling `record_execution_replacement_scan` with a `finalized_cursor` whose `hash` differs from the hash stored in `execution_verified_finalized_header` for the same (chain_id, wallet_address, number).","commonSituations":"A chain reorg replaced the block at that height after it was durably verified; the cursor hash was computed from a different network (wrong chain_id); stale bytes were cached and hashed instead of the verified header.","solutions":["Re-verify the header at that height and rebuild the cursor from the hash stored in `execution_verified_finalized_header`.","If a genuine reorg occurred, run the reorg-handling path to update the finalized header ledger before re-submitting the scan.","Confirm chain_id is correct; a mismatched network produces entirely different hashes at the same height."],"exampleFix":"// before: trusting a cached cursor hash\nlet cursor = cached_cursor.clone();\n// after: adopt the durably verified hash\nlet verified = db.verified_finalized_header(chain_id, wallet, cursor.number).await?;\nlet cursor = ExecutionVerifiedHeader { hash: verified.hash, ..cursor };","handlingStrategy":"validation","validationCode":"let stored = sqlx::query_scalar::<_, String>(\"SELECT hash FROM execution_verified_finalized_header WHERE chain_id=$1 AND wallet_address=$2 AND number=$3\").bind(chain_id).bind(wallet).bind(cursor.number as i64).fetch_optional(&pool).await?;\nif stored.as_deref() != Some(cursor.hash.as_str()) { return Err(anyhow!(\"cursor hash diverges from finalized header ledger\")); }","typeGuard":"fn cursor_hash_matches(cursor: &ExecutionVerifiedHeader, durable_hash: &str) -> bool { cursor.hash == durable_hash }","tryCatchPattern":null,"preventionTips":["Rebuild cursors from the durable header ledger rather than cached RPC responses.","Run reorg handling promptly so divergent hashes are reconciled before scans.","Double-check chain_id when constructing headers; cross-network hashes never match."],"tags":["blockchain","consistency","reorg"],"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"}