{"record":{"id":"7940c4877f6b73ed","repo":"nautechsystems/nautilus_trader","slug":"failed-to-batch-insert-into-pool-fee-protocol-coll","errorCode":null,"errorMessage":"Failed to batch insert into pool_fee_protocol_collect_event table: {e}","messagePattern":"Failed to batch insert into pool_fee_protocol_collect_event table: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":2024,"sourceCode":"            ON CONFLICT (chain_id, transaction_hash, log_index) DO NOTHING\n           \",\n        )\n        .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(&senders[..])\n        .bind(&recipients[..])\n        .bind(&amount0s[..])\n        .bind(&amount1s[..])\n        .execute(&self.pool)\n        .await\n        .map(|_| ())\n        .map_err(|e| {\n            anyhow::anyhow!(\n                \"Failed to batch insert into pool_fee_protocol_collect_event table: {e}\"\n            )\n        })\n    }\n\n    /// Adds a pool snapshot to the database.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the database insert fails.\n    pub async fn add_pool_snapshot(\n        &self,\n        chain_id: u32,\n        dex_name: &DexType,\n        pool_identifier: &PoolIdentifier,\n        snapshot: &PoolSnapshot,\n    ) -> anyhow::Result<()> {\n        sqlx::query(","sourceCodeStart":2006,"sourceCodeEnd":2042,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L2006-L2042","documentation":"Raised when the batched UNNEST INSERT of pool protocol-fee collect events (amount0/amount1) into the `pool_fee_protocol_collect_event` table fails. The sqlx error is wrapped with this prefix; the driver's reason follows it. The event batch is not persisted when this fires.","triggerScenarios":"Executing the protocol-fee-collect batch insert (`.bind(&amount0s[..])`, `.bind(&amount1s[..])`, `.execute(&self.pool)`) when the database rejects it: constraint or type errors on amount columns, mismatched array lengths, or connection failure.","commonSituations":"Amount strings not fitting numeric columns after schema changes; duplicate log replay conflicting with unique keys; stale connections after a Postgres restart; missing migrations in a fresh environment.","solutions":["Check the wrapped `{e}` tail for the underlying sqlx/PostgreSQL error","Confirm amount0s/amount1s and all parallel arrays have identical lengths","Run migrations to align the table schema with the adapter's expectations","Deduplicate the batch or add ON CONFLICT handling for replayed logs","Verify connectivity and pool configuration"],"exampleFix":"// before\n.map_err(|e| {\n    anyhow::anyhow!(\n        \"Failed to batch insert into pool_fee_protocol_collect_event table: {e}\"\n    )\n})\n// after: pre-validate and add row-count context\nassert_eq!(amount0s.len(), amount1s.len());\n.map_err(|e| anyhow::anyhow!(\"Failed to batch insert into pool_fee_protocol_collect_event table (rows={}): {e}\", amount0s.len()))","handlingStrategy":"try-catch","validationCode":"fn validate_protocol_collect_batch(rows: &[PoolFeeProtocolCollectEvent]) -> anyhow::Result<()> {\n    anyhow::ensure!(!rows.is_empty(), \"empty batch\");\n    anyhow::ensure!(rows.iter().all(|r| !r.pool_identifier.is_empty()), \"empty pool id\");\n    Ok(())\n}","typeGuard":"fn is_valid_amount(s: &str) -> bool { !s.is_empty() && s.chars().all(|c| c.is_ascii_digit()) }","tryCatchPattern":"if let Err(e) = insert_pool_fee_protocol_collects(&events).await {\n    tracing::error!(\"protocol-collect batch failed: {e:#}\");\n    if is_transient(&e) { schedule_retry(&events); }\n}","preventionTips":["Pre-validate amount strings against numeric column precision","Deduplicate by (block, tx, log index) for replay safety","Keep schema migrations current","Monitor pool health and retry transient driver errors"],"tags":["database","postgres","sqlx","batch-insert"],"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"}