{"record":{"id":"fa3d0f9b765c25c0","repo":"nautechsystems/nautilus_trader","slug":"failed-to-validate-finalized-header-ledger-e","errorCode":null,"errorMessage":"Failed to validate finalized header ledger: {e}","messagePattern":"Failed to validate finalized header ledger: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":4497,"sourceCode":"            .bind(timestamp)\n            .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\")","sourceCodeStart":4479,"sourceCodeEnd":4515,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L4479-L4515","documentation":"This error wraps a sqlx/PostgreSQL failure on the read-back verification SELECT that follows each header insert during ledger extension. After inserting a header, the code immediately re-selects the stored (hash, parent_hash, timestamp, base_fee_per_gas, manifest_digest) row by (chain_id, wallet_address, number) using `fetch_one` and maps any query error to this message. The read-back exists to prove the durable row matches what was written; failing to even execute the read (connection, timeout, missing table) surfaces here.","triggerScenarios":"PostgreSQL errors on the verification SELECT inside the bootstrap transaction: connection loss mid-transaction, statement timeout, relation `execution_verified_finalized_header` missing (schema not migrated), permission denied on SELECT, or the transaction aborted by a prior error leaving the connection in a failed state.","commonSituations":"Deploying a new adapter version against a database that has not run migrations; read-only replica or restricted role lacking SELECT on the table; long-running transaction exceeding idle-in-transaction/statement timeouts during a big bootstrap; transient network failure between insert and verification.","solutions":["Inspect the wrapped `{e}` cause to determine whether it is connectivity, timeout, permission, or missing relation.","Run pending schema migrations so `execution_verified_finalized_header` exists with the expected columns.","Grant SELECT on the table to the database role used by the adapter, and verify you are not pointed at a read-only replica during a write transaction.","Increase statement/idle-in-transaction timeouts or shrink the batch so the insert+verify pair completes within limits.","Retry the bootstrap on transient connection errors; the transaction design makes it safe to re-run."],"exampleFix":"// before: verification read with no timeout budget on huge batches\nlet stored = sqlx::query_as::<_, Row>(SELECT ...).fetch_one(&mut *tx).await?;\n\n// after: give the verification read an explicit statement timeout\nsqlx::query(\"SET LOCAL statement_timeout = '30s'\").execute(&mut *tx).await?;\nlet stored = sqlx::query_as::<_, Row>(SELECT ...)\n    .fetch_one(&mut *tx).await\n    .context(\"ledger verification read failed\")?;","handlingStrategy":"try-catch","validationCode":"let can_read = sqlx::query(\n    \"SELECT has_table_privilege(current_user, 'execution_verified_finalized_header', 'SELECT')\",\n).fetch_one(&pool).await?;\nif !can_read.get::<bool, _>(0) {\n    return Err(anyhow!(\"db role lacks SELECT on execution_verified_finalized_header\"));\n}","typeGuard":null,"tryCatchPattern":"match verify_stored_header(&mut tx, chain_id, wallet, number).await {\n    Err(e) if e.to_string().contains(\"Failed to validate finalized header ledger\") => {\n        // check connectivity/schema/permissions, then retry whole bootstrap\n        Err(anyhow!(\"verification read failed: {e:#}\")).context(\"bootstrap aborted\")\n    }\n    other => other,\n}","preventionTips":["Grant the adapter role SELECT on the ledger table; never point writes at read-only replicas.","Apply schema migrations before upgrading the adapter.","Set realistic statement/idle-in-transaction timeouts for insert+verify pairs.","Alert on connection-pool exhaustion during bootstrap."],"tags":["database","postgres","sqlx","read-failure"],"backgroundTag":"database-query-failed","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"}