aaif-goose/goose · warning

Download is being cancelled; wait for it to finish before re

Error message

Download is being cancelled; wait for it to finish before restarting

What it means

Thrown by download_model_sharded_with_bearer_token (and its download_model / download_model_sharded wrappers) when the shared progress map already holds an entry for the same model_id whose status is Cancelled while task_exited is still false. cancel_download() only flips the status flag; the spawned download task notices it at its next checkpoint (between shards, before each HTTP request, every <=500ms of backoff sleep, or after each streamed chunk), deletes .partial files, and only then sets task_exited = true. This error is the guard against racing a restart against an in-flight cancellation.

Source

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

        model_id: String,
        files: Vec<(String, PathBuf)>,
        total_size_hint: u64,
        bearer_token: Option<String>,
        on_complete: Option<Box<dyn FnOnce() + Send + 'static>>,
    ) -> Result<()> {
        info!(model_id = %model_id, file_count = files.len(), "Starting model download");
        {
            let mut downloads = self
                .downloads
                .lock()
                .map_err(|_| anyhow::anyhow!("Failed to acquire lock"))?;

            if let Some(existing) = downloads.get(&model_id) {
                if existing.status == DownloadStatus::Downloading {
                    anyhow::bail!("Download already in progress");
                }
                if existing.status == DownloadStatus::Cancelled && !existing.task_exited {
                    anyhow::bail!(
                        "Download is being cancelled; wait for it to finish before restarting"
                    );
                }
            }

            downloads.insert(
                model_id.clone(),
                DownloadProgress {
                    model_id: model_id.clone(),
                    status: DownloadStatus::Downloading,
                    bytes_downloaded: 0,
                    total_bytes: total_size_hint,
                    progress_percent: 0.0,
                    speed_bps: None,
                    eta_seconds: None,
                    error: None,
                    task_exited: false,
                },

View on GitHub (pinned to 3810898a74)

Solutions

  1. Poll get_progress(model_id) until task_exited == true (or the entry leaves the Cancelled state) before calling download again
  2. Drive the restart off the progress state instead of a fixed sleep after cancel_download
  3. Only start a new download under a different model_id if you genuinely want an independent concurrent download

Example fix

// before
manager.cancel_download(model_id)?;
manager.download_model(model_id.into(), url, dest, None).await?;

// after: wait for the cancelled task to settle
manager.cancel_download(model_id)?;
while let Some(p) = manager.get_progress(model_id) {
    if p.task_exited { break; }
    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
}
manager.download_model(model_id.into(), url, dest, None).await?;
Defensive patterns

Strategy: validation

Validate before calling

// check the progress map before restarting a cancelled download
fn can_restart(manager: &DownloadManager, model_id: &str) -> bool {
    match manager.get_progress(model_id) {
        None => true,
        Some(p) => p.task_exited && p.status != DownloadStatus::Downloading,
    }
}

Try / catch

match manager.download_model_sharded(...).await {
    Err(e) if e.to_string().contains("wait for it to finish") => {
        // poll get_progress until task_exited, then retry the call once
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling cancel_download(model_id) and immediately calling download_model / download_model_sharded[_with_bearer_token] again with the same model_id before the background task has observed the cancel and set task_exited = true. The window is widest for multi-shard GGUF downloads where checkpoints are far apart.

Common situations: A UI 'Cancel' button handler that auto-restarts the download in the same tick; a retry loop that treats the Cancelled status as restartable without waiting; test code that cancels and restarts back-to-back.

Related errors


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