nautechsystems/nautilus_trader · error · anyhow::Error

Failed to batch insert into pool_flash_event table: {e}

Error message

Failed to batch insert into pool_flash_event table: {e}

What it means

Raised when a batched UNNEST INSERT of pool flash events (with paid0/paid1 amounts) into the `pool_flash_event` table fails. The sqlx execution error is wrapped in anyhow with this message; the driver error text follows the prefix. The flash-event batch is not persisted when this fires.

Source

Thrown at crates/adapters/blockchain/src/cache/database.rs:1861

           ",
        )
        .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[..])
        .bind(&paid0s[..])
        .bind(&paid1s[..])
        .execute(&self.pool)
        .await
        .map(|_| ())
        .map_err(|e| anyhow::anyhow!("Failed to batch insert into pool_flash_event table: {e}"))
    }

    /// Inserts multiple pool fee-protocol update events in a single database operation using UNNEST.
    ///
    /// # Errors
    ///
    /// Returns an error if the database operation fails.
    pub async fn add_pool_fee_protocol_updates_batch(
        &self,
        chain_id: u32,
        updates: &[PoolFeeProtocolUpdate],
    ) -> anyhow::Result<()> {
        if updates.is_empty() {
            return Ok(());
        }

        // Prepare vectors for each column
        let len = updates.len();

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the wrapped `{e}` suffix for the underlying sqlx/PostgreSQL error
  2. Confirm all bound arrays (identifiers, blocks, amounts, paid0s, paid1s, ...) share the same length
  3. Run schema migrations so `pool_flash_event` columns match the bound fields
  4. Check database connectivity and pool configuration
  5. Add ON CONFLICT handling or deduplicate the batch if unique-constraint errors appear

Example fix

// before
.map_err(|e| anyhow::anyhow!("Failed to batch insert into pool_flash_event table: {e}"))
// after: guard against length mismatch before execution
assert_eq!(paid0s.len(), paid1s.len());
.map_err(|e| anyhow::anyhow!("Failed to batch insert into pool_flash_event table (rows={}): {e}", paid0s.len()))
Defensive patterns

Strategy: try-catch

Validate before calling

fn validate_flash_batch(rows: &[PoolFlashEvent]) -> anyhow::Result<()> {
    anyhow::ensure!(!rows.is_empty(), "empty flash batch");
    anyhow::ensure!(rows.iter().all(|r| !r.transaction_hash.is_empty()), "missing tx hash");
    Ok(())
}

Type guard

fn is_non_empty(s: &Option<String>) -> bool { s.as_ref().map_or(false, |v| !v.is_empty()) }

Try / catch

if let Err(e) = insert_pool_flash_events(&events).await {
    tracing::error!("flash batch insert failed: {e:#}");
    if is_transient(&e) { retry_with_backoff(&events).await?; }
}

Prevention

When it happens

Trigger: Executing the multi-row flash-event insert (`.bind(&amount1s[..])`, `.bind(&paid0s[..])`, `.bind(&paid1s[..])`, `.execute(&self.pool)`) when Postgres rejects it: constraint violation, type coercion failure on amount strings, array-length mismatch, or connection failure.

Common situations: Amount strings exceeding the numeric column's precision after a schema change; mismatched vector lengths when the event batch is assembled; dead pool connections after idle timeouts; concurrent writers causing unique/PK conflicts.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/0b4b44ffbd611939. Report an issue: GitHub.