{"record":{"id":"b6e98cc18d6577c6","repo":"aaif-goose/goose","slug":"download-not-found","errorCode":null,"errorMessage":"Download not found","messagePattern":"Download not found","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/goose-download-manager/src/lib.rs","lineNumber":162,"sourceCode":"    pub fn update_progress(&self, model_id: &str, update: impl FnOnce(&mut DownloadProgress)) {\n        if let Ok(mut downloads) = self.downloads.lock() {\n            if let Some(progress) = downloads.get_mut(model_id) {\n                update(progress);\n            }\n        }\n    }\n\n    pub fn cancel_download(&self, model_id: &str) -> Result<()> {\n        let mut downloads = self\n            .downloads\n            .lock()\n            .map_err(|_| anyhow::anyhow!(\"Failed to acquire lock\"))?;\n\n        if let Some(progress) = downloads.get_mut(model_id) {\n            progress.status = DownloadStatus::Cancelled;\n            Ok(())\n        } else {\n            anyhow::bail!(\"Download not found\")\n        }\n    }\n\n    pub async fn download_model(\n        &self,\n        model_id: String,\n        url: String,\n        destination: PathBuf,\n        on_complete: Option<Box<dyn FnOnce() + Send + 'static>>,\n    ) -> Result<()> {\n        self.download_model_sharded(model_id, vec![(url, destination)], 0, on_complete)\n            .await\n    }\n\n    pub async fn download_model_with_bearer_token(\n        &self,\n        model_id: String,\n        url: String,","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-download-manager/src/lib.rs#L144-L180","documentation":"cancel_download flips a record's status to Cancelled only when an entry exists for model_id. Unknown ids, entries removed after completion (clear_completed), or races where the entry was already removed fail with 'Download not found'.","triggerScenarios":"Calling cancel_download after the download finished and its entry was cleared, with a mistyped model_id, or racing another path that removed the entry.","commonSituations":"UIs issuing cancel after a completion event arrives out of order; model_id strings that differ between start and cancel call sites.","solutions":["Check current state first with get_progress(model_id) or is_downloading(model_id)","Treat 'not found' as already-finished and make it a no-op at the call site","Ensure the exact same model_id string is used to start and cancel"],"exampleFix":"// before\nmanager.cancel_download(&model_id)?;\n// after\nif manager.get_progress(&model_id).is_some() {\n    manager.cancel_download(&model_id)?;\n}","handlingStrategy":"validation","validationCode":"if manager.get_progress(&model_id).is_some() {\n    manager.cancel_download(&model_id)?;\n} else {\n    // nothing to cancel: already finished or never started\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = manager.cancel_download(&model_id) {\n    if e.to_string() == \"Download not found\" {\n        return Ok(()); // treat as already finished\n    }\n    return Err(e);\n}","preventionTips":["Check get_progress(model_id) before cancelling","Use the identical model_id string for start and cancel","Make UIs ignore 'not found' on cancel paths triggered by completion races"],"tags":["download","state","validation"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}