{"record":{"id":"f21423fd0b760e98","repo":"nautechsystems/nautilus_trader","slug":"verified-finalized-header-extension-does-not-start","errorCode":null,"errorMessage":"Verified finalized header extension does not start at the durable tip","messagePattern":"Verified finalized header extension does not start at the durable tip","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":4433,"sourceCode":"        );\n\n        if initialized {\n            let stored_tip =\n                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(bootstrap.wallet_address)\n                .fetch_one(&mut *transaction)\n                .await\n                .map_err(|e| anyhow::anyhow!(\"Failed to lock finalized header tip: {e}\"))?;\n            anyhow::ensure!(\n                stored_tip\n                    == (\n                        i64::try_from(first_header.number)\n                            .context(\"Verified finalized height exceeds PostgreSQL BIGINT\")?,\n                        first_header.hash.clone(),\n                        first_header.parent_hash.clone(),\n                        i64::try_from(first_header.timestamp)\n                            .context(\"Verified finalized timestamp exceeds PostgreSQL BIGINT\")?,\n                        first_header.base_fee_per_gas.map(|value| value.to_string()),\n                        bootstrap.manifest_digest.to_string(),\n                    ),\n                \"Verified finalized header extension does not start at the durable tip\"\n            );\n        } else {\n            anyhow::ensure!(\n                first_header.number == bootstrap.checkpoint_number\n                    && first_header.hash == bootstrap.checkpoint_hash\n                    && first_header.parent_hash == bootstrap.checkpoint_parent_hash","sourceCodeStart":4415,"sourceCodeEnd":4451,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L4415-L4451","documentation":"This error is raised while extending the durable `execution_verified_finalized_header` ledger during a verified-finalized bootstrap in PostgreSQL. When the ledger is already initialized (rows exist), the code reads the durable tip (highest-numbered header for this chain_id/wallet_address) and `anyhow::ensure!`s that the first header of the incoming verified batch is byte-identical to that tip (number, hash, parent_hash, timestamp, base_fee, manifest_digest). If it differs, the new batch would create a gap or a fork in the on-disk ledger, so the write is aborted inside the transaction. It is a data-integrity guard against appending finalized headers that do not contiguously extend the stored chain.","triggerScenarios":"Calling the bootstrap/persist routine for verified finalized headers when the ledger already has rows (`initialized == true`) and the first header in `bootstrap.finalized_headers` does not exactly match the stored tip: wrong starting height (gap), different hash at same height (fork/reorg not represented in ledger), differing parent_hash/timestamp/base_fee_per_gas, or a mismatched `bootstrap.manifest_digest` (e.g. bootstrapping from a different manifest than the one recorded).","commonSituations":"Pointing the adapter at a database previously populated by a different deployment/manifest; resuming from a snapshot/pruned node whose verified-finalized range starts later than the stored tip; a chain reorg after the tip was durably recorded; switching RPC providers or consensus checkpoints so the verified header set starts elsewhere; running two writers against the same (chain_id, wallet_address) ledger.","solutions":["Compare the first verified header (number, hash, parent_hash, timestamp, base_fee) with the durable tip via `SELECT number, hash, parent_hash, timestamp, base_fee_per_gas, manifest_digest FROM execution_verified_finalized_header WHERE chain_id=$1 AND wallet_address=$2 ORDER BY number DESC LIMIT 1` to identify the exact mismatching field.","If the manifest changed, re-run the full bootstrap with the manifest digest that is stored in the ledger, or wipe and re-initialize the ledger for this (chain_id, wallet_address) from a trusted checkpoint.","If there is a height gap, fetch verified finalized headers starting exactly at stored_tip.number + 1 (contiguous extension) instead of skipping ahead.","If a reorg occurred, rebuild the ledger from the last common ancestor / trusted checkpoint rather than appending the divergent branch.","Ensure only one writer process owns the ledger for a given chain_id and wallet_address."],"exampleFix":"// before: bootstrap starts at an arbitrary verified height\nlet headers = fetch_verified_finalized(from: latest_snapshot_number);\npersist_finalized_headers(headers);\n\n// after: start exactly at the durable tip so the extension is contiguous\nlet tip = query_durable_tip(chain_id, wallet_address).await?;\nlet headers = fetch_verified_finalized(from: tip.number); // headers[0] == tip\nassert_eq!(headers[0].hash, tip.hash, \"batch must extend the durable tip\");\npersist_finalized_headers(headers).await?;","handlingStrategy":"validation","validationCode":"let tip: Option<(i64, String, String, i64, Option<String>, String)> = sqlx::query_as(\n    \"SELECT number, hash, parent_hash, timestamp, base_fee_per_gas, manifest_digest \\\n     FROM execution_verified_finalized_header WHERE chain_id=$1 AND wallet_address=$2 \\\n     ORDER BY number DESC LIMIT 1\",\n).bind(chain_id).bind(wallet_address).fetch_optional(&pool).await?;\nif let Some(tip) = tip {\n    assert_eq!(tip.0, first.number as i64, \"batch must start at durable tip height\");\n    assert_eq!(tip.1, first.hash, \"batch must start at durable tip hash\");\n}","typeGuard":"fn extends_durable_tip(tip: &TipRow, first: &VerifiedHeader, manifest: &str) -> bool {\n    tip.number == first.number as i64\n        && tip.hash == first.hash\n        && tip.parent_hash == first.parent_hash\n        && tip.timestamp == first.timestamp as i64\n        && tip.base_fee_per_gas == first.base_fee_per_gas.as_ref().map(|v| v.to_string())\n        && tip.manifest_digest == manifest\n}","tryCatchPattern":"match bootstrap_verified_finalized(&pool, &bootstrap).await {\n    Err(e) if e.to_string().contains(\"does not start at the durable tip\") => {\n        // inspect stored tip, realign batch start or rebuild ledger\n    }\n    Err(e) => return Err(e),\n    Ok(()) => {}\n}","preventionTips":["Always fetch the durable tip before selecting the verified batch start height.","Keep one writer per (chain_id, wallet_address) ledger.","Pin and record the manifest digest; never mix batches across manifests.","Monitor for reorgs before resuming an extension."],"tags":["database","consistency","blockchain","data-integrity"],"backgroundTag":"invalid-state-transition","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"}