{"record":{"id":"5110cabe5ef36a2b","repo":"aaif-goose/goose","slug":"download-already-in-progress","errorCode":null,"errorMessage":"Download already in progress","messagePattern":"Download already in progress","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/goose-download-manager/src/lib.rs","lineNumber":229,"sourceCode":"\n    pub async fn download_model_sharded_with_bearer_token(\n        &self,\n        model_id: String,\n        files: Vec<(String, PathBuf)>,\n        total_size_hint: u64,\n        bearer_token: Option<String>,\n        on_complete: Option<Box<dyn FnOnce() + Send + 'static>>,\n    ) -> Result<()> {\n        info!(model_id = %model_id, file_count = files.len(), \"Starting model download\");\n        {\n            let mut downloads = self\n                .downloads\n                .lock()\n                .map_err(|_| anyhow::anyhow!(\"Failed to acquire lock\"))?;\n\n            if let Some(existing) = downloads.get(&model_id) {\n                if existing.status == DownloadStatus::Downloading {\n                    anyhow::bail!(\"Download already in progress\");\n                }\n                if existing.status == DownloadStatus::Cancelled && !existing.task_exited {\n                    anyhow::bail!(\n                        \"Download is being cancelled; wait for it to finish before restarting\"\n                    );\n                }\n            }\n\n            downloads.insert(\n                model_id.clone(),\n                DownloadProgress {\n                    model_id: model_id.clone(),\n                    status: DownloadStatus::Downloading,\n                    bytes_downloaded: 0,\n                    total_bytes: total_size_hint,\n                    progress_percent: 0.0,\n                    speed_bps: None,\n                    eta_seconds: None,","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-download-manager/src/lib.rs#L211-L247","documentation":"download_model_sharded refuses to start when an entry for model_id already has status Downloading, rejecting duplicate concurrent starts for the same model rather than deduplicating them. The companion reserve_download path exists so callers can do this check-and-insert atomically.","triggerScenarios":"Two concurrent download_model calls with the same model_id — double-triggered UI actions, retries that fire before the first attempt exits, parallel automation starting the same model.","commonSituations":"Front-ends firing start twice on double-click; retry logic that treats a slow start as failed and restarts immediately.","solutions":["Poll progress (get_progress / list_progress) and wait for the existing download instead of starting again","Cancel the running download first if a restart is intended, then wait for task_exited","Guard call sites so only one start per model_id is in flight"],"exampleFix":"// before\nmanager.download_model_sharded(model_id.clone(), files, size, token, None).await?;\n// after\nif manager.is_downloading(&model_id) {\n    // already running: poll list_progress() until it finishes\n    return Ok(());\n}\nmanager.download_model_sharded(model_id.clone(), files, size, token, None).await?;","handlingStrategy":"validation","validationCode":"if manager.is_downloading(&model_id) {\n    // a download is already running; poll instead of starting a duplicate\n    poll_until_finished(&manager, &model_id).await;\n} else {\n    manager.download_model_sharded(model_id.clone(), files, size, token, None).await?;\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = manager.download_model_sharded(id, files, size, token, None).await {\n    if e.to_string() == \"Download already in progress\" {\n        poll_until_finished(&manager, &id).await;\n        return Ok(());\n    }\n    return Err(e);\n}","preventionTips":["Debounce start actions in UIs so double-clicks cannot double-start","Check is_downloading(model_id) before initiating a download","In retry logic, distinguish 'already running' from 'failed' before restarting"],"tags":["download","concurrency","validation"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}