nautechsystems/nautilus_trader · error · anyhow::Error

Failed to sync pools: {e}

Error message

Failed to sync pools: {e}

What it means

Wraps errors from `data_client.sync_exchange_pools(&dex_type, 0, None, reset)` after the DEX exchange was successfully registered in `run_sync_dex`. Pool sync walks on-chain factory/pool events from block 0 to the latest block through the node RPC, so RPC failures, reorg-related errors, or client-side database write failures are reported here. The CLI aborts the command.

Source

Thrown at crates/cli/src/blockchain/sync.rs:120

        .http_rpc_url(rpc_http_url.into())
        .maybe_multicall_calls_per_rpc_request(multicall_calls_per_rpc_request)
        .use_hypersync_for_live_data(true)
        .postgres_cache_database_config(postgres_connect_options)
        .build();
    let cancellation_token = tokio_util::sync::CancellationToken::new();
    let mut data_client = BlockchainDataClientCore::new(config, None, None, cancellation_token);
    data_client.initialize_cache_database().await;

    data_client.cache.initialize_chain().await;
    data_client
        .register_dex_exchange(dex_type)
        .await
        .map_err(|e| anyhow::anyhow!("Failed to register DEX exchange: {e}"))?;
    // We want to have full pool sync, so from 0 to last.
    data_client
        .sync_exchange_pools(&dex_type, 0, None, reset)
        .await
        .map_err(|e| anyhow::anyhow!("Failed to sync pools: {e}"))?;

    Ok(())
}

pub(crate) async fn run_sync_blocks(
    chain: String,
    from_block: Option<u64>,
    to_block: Option<u64>,
    database: DatabaseConfig,
) -> anyhow::Result<()> {
    let chain = Chain::from_chain_name(&chain)
        .ok_or_else(|| anyhow::anyhow!("Invalid chain name: {chain}"))?;
    let chain = Arc::new(chain.to_owned());
    let from_block = from_block.unwrap_or(0);

    let postgres_connect_options = get_postgres_connect_options(
        database.host,
        database.port,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Retry the command; the sync is resumable/resettable — use the reset flag only if data is inconsistent.
  2. Switch to a paid/dedicated or local archive node to avoid rate limiting and pruned-state errors during the 0-to-latest backfill.
  3. Check Postgres/cache database connectivity and disk space; a long sync can fail on DB write errors.
  4. Sync a smaller block range (or a single DEX) first to isolate whether the failure is RPC- or data-related.
  5. Inspect the inner `{e}` message with debug logging to target the actual failing call.
Defensive patterns

Strategy: retry

Validate before calling

// check DB reachability and node height before syncing
let height = eth_client.block_number().await?;
let pg = sqlx::postgres::PgPool::connect(&db_url).await?;
println!("node at block {height}, db ok");

Try / catch

loop {
    match data_client.sync_exchange_pools(&dex_type, from, None, reset).await {
        Ok(()) => break,
        Err(e) if is_transient(&e) => { backoff().await; continue; }
        Err(e) => { eprintln!("pool sync failed permanently: {e:#}"); break; }
    }
}

Prevention

When it happens

Trigger: Running `nautilus blockchain sync dex` when the node RPC drops mid-backfill, the block range 0..latest is too large for the provider's limits, the chain is reorganizing, or writing pools to the cache database fails.

Common situations: Long initial full-history sync against public rate-limited RPC endpoints (Infura/Alchemy free tier); local node pruning historical state; Postgres down or connection pool exhausted during a long sync; network interruption during a multi-hour backfill.

Related errors


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