nautechsystems/nautilus_trader · error · anyhow::Error

Failed to finalize pool event sync progress: {e}

Error message

Failed to finalize pool event sync progress: {e}

What it means

Wraps a sqlx error from the final UPSERT that records the pool event sync version and last synced block, completing the transaction started for event-family checkpoints. Failure rolls back the entire transaction via `transaction.commit().await?` semantics — actually the rollback occurs on drop — leaving prior checkpoints unapplied.

Source

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

                "
                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())
            .bind(pool_identifier.as_ref())
            .bind(version as i32)
            .bind(block_number as i64)
            .execute(&mut *transaction)
            .await
            .map_err(|e| anyhow::anyhow!("Failed to finalize pool event sync progress: {e}"))?;
        }

        transaction.commit().await?;
        Ok(())
    }

    /// Retrieves the maximum block number from a specific table for a given pool.
    /// This is useful to detect orphaned data where events were inserted but progress wasn't updated.
    ///
    /// # Errors
    ///
    /// Returns an error if the database query fails.
    pub async fn get_table_last_block(
        &self,
        chain_id: u32,
        table_name: &str,
        pool_identifier: &PoolIdentifier,
    ) -> anyhow::Result<Option<u64>> {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Retry the full transaction on deadlock/serialization errors
  2. Run migrations to ensure the pool event sync state table exists
  3. Keep the transaction short and avoid external I/O inside it
  4. Check Postgres logs for the concrete server-side error
Defensive patterns

Strategy: retry

Validate before calling

sqlx::query("SELECT 1 FROM pool_event_sync_state LIMIT 1").fetch_optional(&pool).await?;

Try / catch

if let Err(e) = finalize_pool_event_sync(...).await {
    if is_transient(&e) { retry_with_backoff(...).await? } else { return Err(e) }
}

Prevention

When it happens

Trigger: Calling the finalize/commit path when the connection is lost mid-transaction, the state table is missing, or the server aborts the transaction (deadlock, serialization failure, statement timeout).

Common situations: Concurrent indexers finalizing the same pool causing deadlocks; long transactions hitting idle_in_transaction_session_timeout; missing migrations on fresh deployments.

Related errors


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