nautechsystems/nautilus_trader · error · anyhow::Error

Failed to update {event_family} pool event-family checkpoint

Error message

Failed to update {event_family} pool event-family checkpoint: {e}

What it means

Wraps a sqlx error from the UPDATE of a single event-family checkpoint inside the transaction that finalizes pool event sync progress. Because it runs in a transaction, failure causes the whole progress update to roll back (the caller should see the transaction abort).

Source

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

                )
                VALUES ($1, $2, $3, $4, $5)
                ON CONFLICT (chain_id, dex_name, pool_identifier, event_family)
                DO UPDATE SET last_full_sync_block_number =
                    GREATEST(
                        pool_event_sync.last_full_sync_block_number,
                        EXCLUDED.last_full_sync_block_number
                    )
                ",
            )
            .bind(chain_id as i32)
            .bind(dex.to_string())
            .bind(pool_identifier.as_ref())
            .bind(event_family)
            .bind(block_number as i64)
            .execute(&mut *transaction)
            .await
            .map_err(|e| {
                anyhow::anyhow!("Failed to update {event_family} pool event-family checkpoint: {e}")
            })?;
        }

        if let Some(version) = version {
            sqlx::query(
                "
                UPDATE pool
                SET
                    event_sync_version = GREATEST(event_sync_version, $4),
                    last_full_sync_block_number =
                        GREATEST(COALESCE(last_full_sync_block_number, $5), $5)
                WHERE chain_id = $1
                AND dex_name = $2
                AND pool_identifier = $3
                ",
            )
            .bind(chain_id as i32)
            .bind(dex.to_string())

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Retry the whole transaction on transient errors (deadlock/serialization) — transactions are atomic so partial state is impossible
  2. Ensure migrations created the event-family checkpoint table
  3. Reduce concurrency or use smaller transactions if deadlocks recur
  4. Log event_family and pool identifier alongside the sqlx error for diagnosis
Defensive patterns

Strategy: retry

Validate before calling

// Verify checkpoint table exists before opening the transaction
sqlx::query("SELECT 1 FROM pool_event_family_checkpoints LIMIT 1").fetch_optional(&pool).await?;

Try / catch

match update_pool_event_sync_progress(...).await {
    Err(e) if is_deadlock_or_serialization(&e) => retry_transaction(...).await?,
    Err(e) => return Err(e),
    Ok(()) => {}
}

Prevention

When it happens

Trigger: Calling `update_pool_event_sync_progress` (or similar) with an event_family when the connection drops mid-transaction, the checkpoint table is missing, or a constraint fails; the dynamic `{event_family}` label comes from the in-flight family name.

Common situations: Migrations not applied; serialization/deadlock failures when many pools finalize concurrently; connection stolen by pool timeout during a long transaction.

Related errors


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