nautechsystems/nautilus_trader · error · anyhow::Error

Failed to insert into pool_swap table: {e}

Error message

Failed to insert into pool_swap table: {e}

What it means

Wraps a failed sqlx INSERT into the `pool_swap` table, which persists pool swap transaction events. The real Postgres error is embedded in the message. It is raised whenever the swap-event insert query cannot complete (constraint, connection, or type error).

Source

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

        .bind(swap.transaction_hash.as_str())
        .bind(swap.transaction_index as i32)
        .bind(swap.log_index as i32)
        .bind(swap.sender.to_string())
        .bind(swap.recipient.to_string())
        .bind(swap.sqrt_price_x96.to_string())
        .bind(swap.liquidity.to_string())
        .bind(swap.tick)
        .bind(swap.amount0.to_string())
        .bind(swap.amount1.to_string())
        .bind(order_side)
        .bind(base_quantity)
        .bind(quote_quantity)
        .bind(spot_price)
        .bind(execution_price)
        .execute(&self.pool)
        .await
        .map(|_| ())
        .map_err(|e| anyhow::anyhow!("Failed to insert into pool_swap table: {e}"))
    }

    /// Persists a liquidity position change (mint/burn) event to the `pool_liquidity` table.
    ///
    /// # Errors
    ///
    /// Returns an error if the database operation fails.
    pub async fn add_pool_liquidity_update(
        &self,
        chain_id: u32,
        liquidity_update: &PoolLiquidityUpdate,
    ) -> anyhow::Result<()> {
        sqlx::query(
            "
            INSERT INTO pool_liquidity_event (
                chain_id, dex_name, pool_identifier, block, transaction_hash, transaction_index, log_index,
                event_type, sender, owner, position_liquidity, amount0, amount1, tick_lower, tick_upper
            ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the embedded Postgres error for the failing constraint (e.g. pool_id FK) and insert the parent pool row first.
  2. If it is a FK/ordering problem, ensure pool records are persisted before their swaps, or add the pool with ON CONFLICT DO NOTHING.
  3. Check bound numeric types (spot_price, execution_price, quantities) match column precision/scale.
  4. Validate pool connectivity and that the `pool_swap` table exists via current migrations.

Example fix

// before: insert swaps unconditionally
.map_err(|e| anyhow::anyhow!("Failed to insert into pool_swap table: {e}"))
// after: guard that the pool exists before persisting its swap
if self.load_pool(chain, dex_id, pool_identifier).await?.is_some() {
    self.insert_pool_swap(/* ... */).await?;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure the referenced pool exists before writing its swap
let pool_exists: Option<(i64,)> = sqlx::query_as(
    "SELECT 1 FROM pool WHERE chain_id = $1 AND pool_address = $2",
)
.bind(chain_id).bind(pool_address)
.fetch_optional(&pool).await?;
if pool_exists.is_none() { return Err(anyhow!("pool {pool_address} not persisted yet")); }

Try / catch

match self.insert_pool_swap(/* ... */).await {
    Ok(()) => {}
    Err(e) if e.to_string().contains("foreign key") => log::warn!("swap for unknown pool dropped: {e}"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling the swap-persistence method (database.rs, insert into `pool_swap`) with values that violate the table schema: e.g. a foreign-key violation because the pool row does not exist yet, a NOT NULL column receiving a missing quantity/price, or oversized U256/decimal values that overflow the column type.

Common situations: Storing swaps before the corresponding pool was inserted (FK violation); a token with wrong decimals causing quantity parsing errors; DB connection idle-timed out mid-sync; column length/type mismatch after a schema change.

Related errors


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