{"record":{"id":"713f67636971a7d0","repo":"nautechsystems/nautilus_trader","slug":"failed-to-insert-into-pool-snapshot-table-e","errorCode":null,"errorMessage":"Failed to insert into pool_snapshot table: {e}","messagePattern":"Failed to insert into pool_snapshot table: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":2116,"sourceCode":"        .bind(snapshot.state.fee_protocol as i16)\n        .bind(snapshot.state.fee_protocol0_basis_points.map(|v| v as i32))\n        .bind(snapshot.state.fee_protocol1_basis_points.map(|v| v as i32))\n        .bind(snapshot.state.fee_growth_global_0.to_string())\n        .bind(snapshot.state.fee_growth_global_1.to_string())\n        .bind(snapshot.analytics.total_amount0_deposited.to_string())\n        .bind(snapshot.analytics.total_amount1_deposited.to_string())\n        .bind(snapshot.analytics.total_amount0_collected.to_string())\n        .bind(snapshot.analytics.total_amount1_collected.to_string())\n        .bind(snapshot.analytics.total_swaps as i32)\n        .bind(snapshot.analytics.total_mints as i32)\n        .bind(snapshot.analytics.total_burns as i32)\n        .bind(snapshot.analytics.total_fee_collects as i32)\n        .bind(snapshot.analytics.total_flashes as i32)\n        .bind(snapshot.analytics.liquidity_utilization_rate)\n        .execute(&self.pool)\n        .await\n        .map(|_| ())\n        .map_err(|e| anyhow::anyhow!(\"Failed to insert into pool_snapshot table: {e}\"))\n    }\n\n    /// Inserts multiple pool positions in a single database operation using UNNEST for optimal performance.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the database operation fails.\n    pub async fn add_pool_positions_batch(\n        &self,\n        chain_id: u32,\n        snapshot_block: u64,\n        snapshot_transaction_index: u32,\n        snapshot_log_index: u32,\n        positions: &[(PoolIdentifier, PoolPosition)],\n    ) -> anyhow::Result<()> {\n        if positions.is_empty() {\n            return Ok(());\n        }","sourceCodeStart":2098,"sourceCodeEnd":2134,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L2098-L2134","documentation":"Raised when a single-row INSERT of a pool snapshot into the `pool_snapshot` table (including analytics fields such as total fee-collects, flashes, and liquidity utilization rate) fails. The sqlx error is wrapped with this message. The snapshot is not saved, which can break checkpoint/replay start points that depend on snapshots.","triggerScenarios":"Calling the add-pool-snapshot method when Postgres rejects the row: NOT NULL violation on an analytics field, numeric precision overflow for utilization rate, FK violation if the referenced pool row does not exist yet, or connection loss.","commonSituations":"Inserting a snapshot for a pool not yet present in the pools table (FK failure); utilization-rate floats exceeding column precision; schema drift after migrations; database restarts mid-run.","solutions":["Read the `{e}` suffix for the exact sqlx/PostgreSQL error","Ensure the referenced pool row exists before inserting its snapshot (FK order)","Run pending migrations to match the pool_snapshot schema","Validate analytics fields (non-negative counts, utilization rate within column bounds) before inserting","Check connection health and retry after transient failures"],"exampleFix":"// before\n.map_err(|e| anyhow::anyhow!(\"Failed to insert into pool_snapshot table: {e}\"))\n// after: ensure parent row exists and surface pool context\n// ensure pool row for snapshot.pool_identifier is inserted first\n.map_err(|e| anyhow::anyhow!(\"Failed to insert into pool_snapshot table (pool={}, block={}): {e}\", snapshot.pool_identifier, snapshot.block))","handlingStrategy":"try-catch","validationCode":"fn validate_snapshot(snapshot: &PoolSnapshot) -> anyhow::Result<()> {\n    anyhow::ensure!(!snapshot.pool_identifier.is_empty(), \"missing pool_identifier\");\n    anyhow::ensure!(snapshot.analytics.liquidity_utilization_rate >= 0.0, \"negative utilization\");\n    Ok(())\n}","typeGuard":"fn is_persistable(snapshot: &PoolSnapshot) -> bool {\n    !snapshot.pool_identifier.is_empty() && snapshot.block > 0\n}","tryCatchPattern":"match add_pool_snapshot(&snapshot).await {\n    Ok(()) => {},\n    Err(e) if e.to_string().contains(\"foreign key\") => {\n        ensure_pool_row(&snapshot.pool_identifier).await?;\n        add_pool_snapshot(&snapshot).await?;\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Insert the parent pool row before its snapshots","Validate analytics fields against column bounds","Run migrations before snapshot writes","Retry transient connection errors with backoff"],"tags":["database","postgres","sqlx","snapshot"],"backgroundTag":"database-write-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"}