nautechsystems/nautilus_trader · error · anyhow::Error
Failed to batch insert into pool_fee_protocol_collect_event
Error message
Failed to batch insert into pool_fee_protocol_collect_event table: {e} What it means
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.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:2024
ON CONFLICT (chain_id, transaction_hash, log_index) DO NOTHING
",
)
.bind(&chain_ids[..])
.bind(&dex_names[..])
.bind(&pool_identifiers[..])
.bind(&blocks[..])
.bind(&transaction_hashes[..])
.bind(&transaction_indices[..])
.bind(&log_indices[..])
.bind(&senders[..])
.bind(&recipients[..])
.bind(&amount0s[..])
.bind(&amount1s[..])
.execute(&self.pool)
.await
.map(|_| ())
.map_err(|e| {
anyhow::anyhow!(
"Failed to batch insert into pool_fee_protocol_collect_event table: {e}"
)
})
}
/// Adds a pool snapshot to the database.
///
/// # Errors
///
/// Returns an error if the database insert fails.
pub async fn add_pool_snapshot(
&self,
chain_id: u32,
dex_name: &DexType,
pool_identifier: &PoolIdentifier,
snapshot: &PoolSnapshot,
) -> anyhow::Result<()> {
sqlx::query(View on GitHub (pinned to 18893faf8b)
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
Example fix
// before
.map_err(|e| {
anyhow::anyhow!(
"Failed to batch insert into pool_fee_protocol_collect_event table: {e}"
)
})
// after: pre-validate and add row-count context
assert_eq!(amount0s.len(), amount1s.len());
.map_err(|e| anyhow::anyhow!("Failed to batch insert into pool_fee_protocol_collect_event table (rows={}): {e}", amount0s.len())) Defensive patterns
Strategy: try-catch
Validate before calling
fn validate_protocol_collect_batch(rows: &[PoolFeeProtocolCollectEvent]) -> anyhow::Result<()> {
anyhow::ensure!(!rows.is_empty(), "empty batch");
anyhow::ensure!(rows.iter().all(|r| !r.pool_identifier.is_empty()), "empty pool id");
Ok(())
} Type guard
fn is_valid_amount(s: &str) -> bool { !s.is_empty() && s.chars().all(|c| c.is_ascii_digit()) } Try / catch
if let Err(e) = insert_pool_fee_protocol_collects(&events).await {
tracing::error!("protocol-collect batch failed: {e:#}");
if is_transient(&e) { schedule_retry(&events); }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Failed to batch insert into pool_fee_collect table: {e}
- Failed to batch insert into pool_flash_event table: {e}
- Failed to batch insert into pool_fee_protocol_update_event t
- Failed to batch insert into pool_position table: {e}
- Failed to batch insert into pool_tick table: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/7940c4877f6b73ed.
Report an issue: GitHub.