nautechsystems/nautilus_trader · info
Sync cancelled
Error message
Sync cancelled
What it means
sync_blocks runs the block fetch loop inside tokio::select! against the client's cancellation token. When cancellation fires (disconnect, reconfiguration, or shutdown), the sync aborts deliberately with Err("Sync cancelled") — it signals an interrupted backfill of historical blocks into the local timestamp cache, not an unexpected failure.
Source
Thrown at crates/adapters/blockchain/src/data/core.rs:427
.request_blocks_stream(from_block, Some(to_block))
.await;
tokio::pin!(blocks_stream);
let mut metrics = BlockchainSyncReporter::new(
BlockchainSyncReportItems::Blocks,
from_block,
total_blocks,
BLOCKS_PROCESS_IN_SYNC_REPORT,
);
let mut batch: Vec<Block> = Vec::with_capacity(BATCH_SIZE);
let cancellation_token = self.cancellation_token.clone();
let sync_result = tokio::select! {
() = cancellation_token.cancelled() => {
log::debug!("Block sync cancelled");
Err(anyhow::anyhow!("Sync cancelled"))
}
result = async {
while let Some(block) = blocks_stream.next().await {
let block_number = block.number;
if self.cache.get_block_timestamp(block_number).is_some() {
continue;
}
batch.push(block);
// Process batch when full or last block
if batch.len() >= BATCH_SIZE || block_number >= to_block {
let batch_size = batch.len();
self.cache.add_blocks_batch(batch, use_copy_command).await?;
metrics.update(batch_size);
// Re-initialize batch vector
batch = Vec::with_capacity(BATCH_SIZE);View on GitHub (pinned to 18893faf8b)
Solutions
- Treat this error as expected cancellation: filter/match for it and log rather than alert.
- Keep the client connected until sync_blocks completes if the cache must be fully populated.
- Re-run sync_blocks_checked after reconnect — cached block timestamps are skipped via cache lookups, so it resumes cheaply.
- If cancellations are unwanted, audit what is triggering the cancellation token (disconnect paths or task restarts).
Example fix
// before
client.sync_blocks_checked(chain, from, to).await?;
// after
if let Err(e) = client.sync_blocks_checked(chain, from, to).await {
if e.to_string() == "Sync cancelled" {
log::info!("block sync cancelled by shutdown");
} else {
return Err(e);
}
} Defensive patterns
Strategy: try-catch
Try / catch
match client.sync_blocks_checked(chain, from, to).await {
Ok(()) => {},
Err(e) if e.to_string() == "Sync cancelled" => log::info!("sync cancelled, will resume"),
Err(e) => return Err(e),
} Prevention
- Keep the client connected until the backfill finishes
- Remember sync is resumable: cached block timestamps are skipped on re-run
- Audit what triggers the cancellation token during long syncs
When it happens
Trigger: Any cancellation of the token while a sync_blocks stream is active: calling disconnect(), starting a new task generation, or dropping the client mid-sync.
Common situations: User-initiated disconnect during a long historical block backfill; reconnect cycles cancelling an in-progress sync; service shutdown while bootstrapping block timestamps.
Related errors
- failed to finish Binance Futures data command tasks: {e}
- failed to finish Binance Spot data command tasks: {e}
- Hyperliquid WebSocket handler failed: {error}
- Hyperliquid WebSocket handler did not stop after abort
- Blockchain process task shutdown failed: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/785121ea46625425.
Report an issue: GitHub.