aaif-goose/goose · info

Download cancelled

Error message

Download cancelled

What it means

Cancellation checkpoint inside cancellable_sleep, the helper that waits out retry backoff. Every <=500ms it re-checks the shared progress map; if cancel_download() set status = Cancelled, it bails with 'Download cancelled', aborting the backoff and the whole download task. The spawn error handler stores the message in DownloadProgress.error but keeps the status Cancelled (it only overwrites status when it is not already Cancelled) and sets task_exited = true.

Source

Thrown at crates/goose-download-manager/src/lib.rs:326

        });

        Ok(())
    }

    const MAX_RETRIES: u32 = 10;
    const RETRY_BASE_DELAY: std::time::Duration = std::time::Duration::from_secs(2);
    const RETRY_MAX_DELAY: std::time::Duration = std::time::Duration::from_secs(60);

    async fn cancellable_sleep(
        delay: std::time::Duration,
        downloads: &DownloadMap,
        model_id: &str,
    ) -> Result<(), anyhow::Error> {
        let check_interval = std::time::Duration::from_millis(500);
        let start = std::time::Instant::now();
        while start.elapsed() < delay {
            if Self::is_cancelled(downloads, model_id) {
                anyhow::bail!("Download cancelled");
            }
            let remaining = delay.saturating_sub(start.elapsed());
            tokio::time::sleep(std::cmp::min(check_interval, remaining)).await;
        }
        Ok(())
    }

    fn is_cancelled(downloads: &DownloadMap, model_id: &str) -> bool {
        if let Ok(downloads) = downloads.lock() {
            if let Some(progress) = downloads.get(model_id) {
                return progress.status == DownloadStatus::Cancelled;
            }
        }
        false
    }

    #[allow(clippy::too_many_arguments)]
    /// Download multiple files sequentially, tracking cumulative progress under one model_id.

View on GitHub (pinned to 3810898a74)

Solutions

  1. Nothing to fix if the cancel was intentional: treat status Cancelled as the source of truth, not this error string
  2. Restart the download once task_exited is true; already-completed shards are skipped on restart
  3. If cancels are unexpected, find the caller invoking cancel_download (UI event, timeout watchdog)
Defensive patterns

Strategy: validation

Validate before calling

// cancellation is a status, not an exception: read the progress map
let user_cancelled = manager.get_progress(model_id)
    .is_some_and(|p| p.status == DownloadStatus::Cancelled);

Try / catch

if let Err(e) = download_result {
    if e.to_string() == "Download cancelled" {
        // expected termination after cancel_download(); show Cancelled state, not an error
    } else {
        // real failure: e is also mirrored in DownloadProgress.error
    }
}

Prevention

When it happens

Trigger: cancel_download() is called while the task is sleeping between retry attempts, i.e. after a connection error or transient HTTP (5xx/408/429) failure put it into exponential backoff (2s doubling, capped 60s).

Common situations: User cancels a download that is already struggling with a flaky network, so the task happens to be in a retry sleep; automated jobs aborting during an HF/CDN outage.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/f3ecd3c6dac6e6db. Report an issue: GitHub.