{"record":{"id":"d201d037eb823be0","repo":"nautechsystems/nautilus_trader","slug":"finalized-header-ledger-conflicts-at-height","errorCode":null,"errorMessage":"Finalized header ledger conflicts at height {}","messagePattern":"Finalized header ledger conflicts at height (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":4498,"sourceCode":"            .bind(&base_fee)\n            .bind(bootstrap.manifest_digest)\n            .execute(&mut *transaction)\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to extend finalized header ledger: {e}\"))?;\n            let stored = sqlx::query_as::<_, (String, String, i64, Option<String>, String)>(\n                \"\n                SELECT 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 AND number = $3\n                \",\n            )\n            .bind(chain_id)\n            .bind(bootstrap.wallet_address)\n            .bind(number)\n            .fetch_one(&mut *transaction)\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to validate finalized header ledger: {e}\"))?;\n            anyhow::ensure!(\n                stored\n                    == (\n                        header.hash.clone(),\n                        header.parent_hash.clone(),\n                        timestamp,\n                        base_fee,\n                        bootstrap.manifest_digest.to_string(),\n                    ),\n                \"Finalized header ledger conflicts at height {}\",\n                header.number\n            );\n        }\n\n        let finalized_height = bootstrap\n            .finalized_headers\n            .last()\n            .expect(\"verified finalized headers are nonempty\")\n            .number;","sourceCodeStart":4480,"sourceCodeEnd":4516,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L4480-L4516","documentation":"This error is raised by the post-insert consistency check: after inserting a verified finalized header, the code re-reads the stored row and `anyhow::ensure!`s it equals the header just written (hash, parent_hash, timestamp, base_fee, manifest_digest). A mismatch means the durable row at that height differs from the verified header — the ledger is said to conflict at that height. Because inserts use `ON CONFLICT DO NOTHING`, a pre-existing divergent row at the same (chain_id, wallet_address, number) silently survives the insert and is caught here. The failing height is included in the message.","triggerScenarios":"A row already exists at `header.number` for this (chain_id, wallet_address) with a different hash/parent_hash/timestamp/base_fee_per_gas/manifest_digest (fork or reorg, or data written by a different manifest); or the write path is subtly corrupting values (e.g. base_fee serialized differently than the SELECT parses it), so the read-back never equals the in-memory header.","commonSituations":"Chain reorg after the conflicting height was durably recorded; two deployments with different manifests sharing one ledger; re-running an old bootstrap against a ledger advanced by a newer version (manifest_digest mismatch); type/serialization drift after an upgrade making timestamp or base_fee comparisons fail.","solutions":["Query the stored row at the reported height (`SELECT * FROM execution_verified_finalized_header WHERE chain_id=$1 AND wallet_address=$2 AND number=$3`) and diff each field against the verified header to see which value conflicts.","If manifest_digest differs, re-run bootstrap with the manifest recorded in the ledger, or rebuild the ledger under the new manifest.","If hash/parent_hash differ, treat it as a fork: rebuild the ledger from the trusted checkpoint or last common ancestor instead of appending.","If only timestamp/base_fee differ, check for serialization/type drift between write and read paths after upgrades and normalize formats.","Ensure a single writer owns each (chain_id, wallet_address) ledger to avoid concurrent divergent writes."],"exampleFix":"// before: silent conflict when the row pre-exists with different data\nINSERT INTO execution_verified_finalized_header (...) VALUES (...)\nON CONFLICT (chain_id, wallet_address, number) DO NOTHING;\n\n// after: make divergence explicit instead of relying on read-back failure\nINSERT INTO execution_verified_finalized_header (...) VALUES (...)\nON CONFLICT (chain_id, wallet_address, number) DO UPDATE\nSET hash = EXCLUDED.hash\nWHERE execution_verified_finalized_header.hash = EXCLUDED.hash; -- no-op if equal; rowcount 0 signals conflict","handlingStrategy":"validation","validationCode":"let stored: Option<(String, String, i64, Option<String>, String)> = sqlx::query_as(\n    \"SELECT hash, parent_hash, timestamp, base_fee_per_gas, manifest_digest \\\n     FROM execution_verified_finalized_header WHERE chain_id=$1 AND wallet_address=$2 AND number=$3\",\n).bind(chain_id).bind(wallet).bind(number as i64).fetch_optional(&pool).await?;\nif let Some(row) = stored {\n    if row.0 != header.hash || row.4 != manifest_digest {\n        return Err(anyhow!(\"pre-insert conflict at height {number}: stored={row:?}\"));\n    }\n}","typeGuard":"fn row_matches_header(row: &StoredRow, h: &VerifiedHeader, manifest: &str) -> bool {\n    row.hash == h.hash\n        && row.parent_hash == h.parent_hash\n        && row.timestamp == h.timestamp as i64\n        && row.base_fee_per_gas == h.base_fee_per_gas.as_ref().map(|v| v.to_string())\n        && row.manifest_digest == manifest\n}","tryCatchPattern":"match extend_finalized_ledger(&mut tx, &bootstrap).await {\n    Err(e) if e.to_string().contains(\"ledger conflicts at height\") => {\n        let height = extract_conflict_height(&e);\n        // diff stored row vs verified header, then rebuild from common ancestor\n        Err(e.context(format!(\"ledger divergence at {height}; rebuild required\")))\n    }\n    other => other,\n}","preventionTips":["Pre-check for existing divergent rows before inserting (ON CONFLICT DO NOTHING hides them).","Track manifest digest per ledger and refuse bootstraps from a different manifest.","Detect reorgs upstream before extending the ledger.","Keep serialization of timestamp/base_fee identical on write and read paths.","Restrict the ledger to a single writer per (chain_id, wallet_address)."],"tags":["database","consistency","blockchain","data-integrity"],"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"}