{"record":{"id":"ac9720a605cf0330","repo":"nautechsystems/nautilus_trader","slug":"failed-to-insert-into-pool-liquidity-table-e","errorCode":null,"errorMessage":"Failed to insert into pool_liquidity table: {e}","messagePattern":"Failed to insert into pool_liquidity table: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":1289,"sourceCode":"        .bind(chain_id as i32)\n        .bind(liquidity_update.dex.name.to_string())\n        .bind(liquidity_update.pool_identifier.as_str())\n        .bind(liquidity_update.block as i64)\n        .bind(liquidity_update.transaction_hash.as_str())\n        .bind(liquidity_update.transaction_index as i32)\n        .bind(liquidity_update.log_index as i32)\n        .bind(liquidity_update.kind.to_string())\n        .bind(liquidity_update.sender.map(|sender| sender.to_string()))\n        .bind(liquidity_update.owner.to_string())\n        .bind(U128Pg(liquidity_update.position_liquidity))\n        .bind(U256Pg(liquidity_update.amount0))\n        .bind(U256Pg(liquidity_update.amount1))\n        .bind(liquidity_update.tick_lower)\n        .bind(liquidity_update.tick_upper)\n        .execute(&self.pool)\n        .await\n        .map(|_| ())\n        .map_err(|e| anyhow::anyhow!(\"Failed to insert into pool_liquidity table: {e}\"))\n    }\n\n    /// Retrieves all valid token records for the given chain and converts them into `Token` domain objects.\n    ///\n    /// Only returns tokens that do not contain error information, filtering out invalid tokens\n    /// that were previously recorded with error details.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the database query fails.\n    pub async fn load_tokens(&self, chain: SharedChain) -> anyhow::Result<Vec<Token>> {\n        sqlx::query_as::<_, TokenRow>(\"SELECT * FROM token WHERE chain_id = $1 AND error IS NULL\")\n            .bind(chain.chain_id as i32)\n            .fetch_all(&self.pool)\n            .await\n            .map(|rows| {\n                rows.into_iter()\n                    .map(|token_row| {","sourceCodeStart":1271,"sourceCodeEnd":1307,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L1271-L1307","documentation":"Wraps a failed sqlx INSERT into the `pool_liquidity` table for mint/burn liquidity position events. Any Postgres-level failure (constraint, type, connection) is converted into this anyhow error. The originating database error text is always included after the colon.","triggerScenarios":"Calling the liquidity-event insert (database.rs, insert into `pool_liquidity`) when a bind fails or the statement errors: FK violation for a missing pool row, NOT NULL on amount0/amount1/tick fields, or U256 liquidity amounts that cannot be stored in the target column type.","commonSituations":"Processing mint/burn events for pools that were filtered out or not yet synced; schema drift between adapter expectations and the deployed migration state; oversized liquidity values from high-volume pools; connection loss during bulk event replay.","solutions":["Check the embedded SQLSTATE/constraint name; for FK violations persist the pool before its liquidity events.","Verify U256 amounts are converted to a column-compatible representation (numeric/bytea) without overflow.","Run pending migrations so `pool_liquidity` matches the query's columns.","If replaying historical ranges, chunk the work and retry on transient connection errors."],"exampleFix":"// before: insert liquidity events for any pool\nself.insert_pool_liquidity(&liquidity_update).await?;\n// after: skip pools absent from the cache\nif self.load_pool(chain, dex_id, &liquidity_update.pool_identifier).await?.is_some() {\n    self.insert_pool_liquidity(&liquidity_update).await?;\n}","handlingStrategy":"try-catch","validationCode":"// check liquidity values fit the column types before writing\nlet liquidity_fits = amount0 <= U256::from(u128::MAX) && amount1 <= U256::from(u128::MAX);\nif !liquidity_fits { return Err(anyhow!(\"liquidity amount exceeds storage column\")); }","typeGuard":null,"tryCatchPattern":"if let Err(e) = self.insert_pool_liquidity(&update).await {\n    if e.to_string().contains(\"foreign key\") {\n        log::warn!(\"liquidity event for unpersisted pool skipped\");\n    } else {\n        return Err(e);\n    }\n}","preventionTips":["Only process liquidity events for pools present in the cache.","Convert U256 amounts with an encoding that matches the column type.","Chunk historical replays and retry transient failures.","Keep migrations current with the adapter version."],"tags":["database","sqlx","postgres","insert-failed"],"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"}