{"record":{"id":"e5c6ede113eaa522","repo":"nautechsystems/nautilus_trader","slug":"failed-to-batch-insert-into-pool-liquidity-event-t","errorCode":null,"errorMessage":"Failed to batch insert into pool_liquidity_event table: {e}","messagePattern":"Failed to batch insert into pool_liquidity_event table: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":1133,"sourceCode":"        .bind(&chain_ids[..])\n        .bind(&dex_names[..])\n        .bind(&pool_identifiers[..])\n        .bind(&blocks[..])\n        .bind(&transaction_hashes[..])\n        .bind(&transaction_indices[..])\n        .bind(&log_indices[..])\n        .bind(&event_types[..])\n        .bind(&senders[..])\n        .bind(&owners[..])\n        .bind(&position_liquidities[..])\n        .bind(&amount0s[..])\n        .bind(&amount1s[..])\n        .bind(&tick_lowers[..])\n        .bind(&tick_uppers[..])\n        .execute(&self.pool)\n        .await\n        .map(|_| ())\n        .map_err(|e| anyhow::anyhow!(\"Failed to batch insert into pool_liquidity_event table: {e}\"))\n    }\n\n    /// Adds or updates a token record in the database.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the database operation fails.\n    pub async fn add_token(&self, token: &Token) -> anyhow::Result<()> {\n        sqlx::query(\n            \"\n            INSERT INTO token (\n                chain_id, address, name, symbol, decimals\n            ) VALUES ($1, $2, $3, $4, $5)\n            ON CONFLICT (chain_id, address)\n            DO UPDATE\n            SET\n                name = $3,\n                symbol = $4,","sourceCodeStart":1115,"sourceCodeEnd":1151,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L1115-L1151","documentation":"UNNEST-based batch insert of liquidity (mint/burn) events into `pool_liquidity_event` failed; wrapped with this message. Thrown when the bulk liquidity-event statement fails to execute against Postgres.","triggerScenarios":"Calling the batch liquidity insert with arrays of differing lengths (amount1s/tick_lowers/tick_uppers vs. other bound arrays), tick values out of the column's range, FK violation when the pool/block rows don't exist, or Postgres connectivity/permission failure during execute.","commonSituations":"Liquidity events persisted before their parent blocks in a crash-recovery path; replayed events tripping unique constraints; tick values from exotic pools exceeding INT column bounds; un-migrated fresh database.","solutions":["Inspect the wrapped `{e}` for the specific constraint, cast, or FK failure","Insert dependent block/pool rows before the liquidity events","Deduplicate or use ON CONFLICT to tolerate replays","Verify equal slice lengths for all bound arrays and that ticks fit the column's integer range"],"exampleFix":"// before\nassert!(amount0s.len() == amount1s.len());\n// after\nassert!(amount0s.len() == amount1s.len() && amount0s.len() == tick_lowers.len() && tick_lowers.len() == tick_uppers.len());","handlingStrategy":"validation","validationCode":"let n = events.len();\nanyhow::ensure!(amount0s.len() == n && amount1s.len() == n && tick_lowers.len() == n && tick_uppers.len() == n, \"liquidity batch arrays misaligned\");\nanyhow::ensure!(tick_lowers.iter().zip(tick_uppers).all(|(l, u)| l <= &i32::MAX as _ && u <= &i32::MAX as _), \"tick out of i32 range\");","typeGuard":"fn liquidity_batch_valid(events: &[LiquidityEvent]) -> bool {\n    events.iter().all(|e| e.tick_lower <= e.tick_upper && e.amount1 >= 0)\n}","tryCatchPattern":"match db.insert_liquidity_events_batch(&events).await {\n    Err(e) if e.to_string().contains(\"duplicate key\") => tracing::debug!(\"liquidity events already persisted\"),\n    Err(e) => return Err(e.context(\"liquidity event batch insert failed\"),),\n    Ok(()) => {}\n}","preventionTips":["Order persistence so parent block/pool rows exist before liquidity events","Verify tick values fit the column's integer range before binding","Keep all UNNEST slices built from a single loop over the events","Make inserts idempotent for crash-recovery replays"],"tags":["database","postgres","sqlx","insert","batch"],"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"}