{"record":{"id":"051bf00a8df378f1","repo":"nautechsystems/nautilus_trader","slug":"failed-to-load-latest-valid-pool-snapshot-e","errorCode":null,"errorMessage":"Failed to load latest valid pool snapshot: {e}","messagePattern":"Failed to load latest valid pool snapshot: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":2419,"sourceCode":"                COALESCE(\n                    (SELECT timestamp::TEXT FROM block WHERE block.chain_id = pool_snapshot.chain_id AND block.number = pool_snapshot.block),\n                    (SELECT timestamp::TEXT FROM pool_event_block WHERE pool_event_block.chain_id = pool_snapshot.chain_id AND pool_event_block.number = pool_snapshot.block)\n                ) as block_timestamp\n            FROM pool_snapshot\n            WHERE chain_id = $1 AND pool_identifier = $2\n                AND ($3::BIGINT IS NULL OR block <= $3)\n                AND ($4 OR validation_state <> 'invalid')\n            ORDER BY block DESC, transaction_index DESC, log_index DESC\n            LIMIT 1\n            \",\n        )\n        .bind(chain_id as i32)\n        .bind(pool_identifier.as_ref())\n        .bind(max_block.map(|b| b as i64))\n        .bind(allow_invalid)\n        .fetch_optional(&self.pool)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to load latest valid pool snapshot: {e}\"))?;\n\n        if let Some(row) = result {\n            // Parse snapshot state\n            let block: i64 = row.get(\"block\");\n            let transaction_index: i32 = row.get(\"transaction_index\");\n            let log_index: i32 = row.get(\"log_index\");\n            let transaction_hash: String = row.get(\"transaction_hash\");\n            let observed_block_hash = row.try_get::<Option<String>, _>(\"block_hash\")?;\n            let block =\n                u64::try_from(block).with_context(|| \"Pool snapshot block number is negative\")?;\n            let transaction_index = u32::try_from(transaction_index)\n                .with_context(|| \"Pool snapshot transaction index is negative\")?;\n            let log_index =\n                u32::try_from(log_index).with_context(|| \"Pool snapshot log index is negative\")?;\n            let block_hash = if transaction_index == BLOCK_SCOPED_SNAPSHOT_INDEX\n                && log_index == BLOCK_SCOPED_SNAPSHOT_INDEX\n            {\n                Some(transaction_hash.clone())","sourceCodeStart":2401,"sourceCodeEnd":2437,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L2401-L2437","documentation":"This error wraps any SQLx failure that occurs while running the query that fetches the most recent valid pool snapshot row from the PostgreSQL snapshot store (`fetch_optional`). The library converts the underlying driver error into an `anyhow` error with this message so callers get pool-snapshot context instead of a bare database error. It means the SELECT itself failed — the row was not simply missing.","triggerScenarios":"Calling the database cache's latest-snapshot loader when the Postgres connection is down, the `pool_snapshots` table/schema is missing or was migrated (column renames break the bound columns `chain_id`, `pool_identifier`, `max_block`, `allow_invalid`), credentials are wrong, or the connection pool has timed out / hit max connections.","commonSituations":"Starting the adapter against a database that has not had migrations applied; Docker Postgres container stopped; stale pooled connections after a database restart/failover; schema drift after upgrading the adapter version; wrong DATABASE_URL in the environment.","solutions":["Verify the database is reachable and credentials in the connection URL are correct (psql with the same URL).","Confirm migrations have been applied and the pool-snapshot table/columns match the adapter's expected schema; run migrations if not.","Check Postgres logs for the underlying error (auth failure, too many connections, lock timeout).","Restart the adapter or recycle the sqlx pool to clear stale connections after a DB restart.","Inspect the chained source error (`{e}`) in the message for the exact driver-level cause."],"exampleFix":"// before: retry on any error\nlet snap = cache.load_latest_valid_snapshot(...).await?;\n// after: check DB availability first and surface the inner error\nlet snap = cache.load_latest_valid_snapshot(...).await\n    .map_err(|e| { tracing::error!(cause = ?e.source(), \"snapshot load failed\"); e })?;","handlingStrategy":"try-catch","validationCode":"let ok = sqlx::any::AnyPool::connect(&url).await.is_ok(); // or run a trivial SELECT 1 against the pool before loading\nassert!(ok, \"database unreachable before snapshot load\");","typeGuard":null,"tryCatchPattern":"match cache.load_latest_valid_snapshot(...).await {\n    Ok(snap) => snap,\n    Err(e) => { tracing::error!(cause = ?e.source(), \"snapshot load failed\"); return Err(e); }\n}","preventionTips":["Run migrations automatically at startup before touching snapshot tables.","Add a health-check SELECT 1 before/at pool creation and on reconnect.","Pin and verify DATABASE_URL per environment; never share dev/prod databases.","Retry transient connection errors with exponential backoff."],"tags":["database","postgres","sqlx","snapshot-loading"],"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-14T00:17:10.932Z"}