{"record":{"id":"fecbf27a3eaf6756","repo":"cjpais/Handy","slug":"no-download-source-for-model","errorCode":null,"errorMessage":"No download source for model","messagePattern":"No download source for model","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"src-tauri/src/managers/model.rs","lineNumber":2170,"sourceCode":"\n    pub async fn download_model(&self, model_id: &str) -> Result<()> {\n        let model_info = {\n            let models = self.available_models.lock().unwrap();\n            models.get(model_id).cloned()\n        };\n\n        let model_info =\n            model_info.ok_or_else(|| anyhow::anyhow!(\"Model not found: {}\", model_id))?;\n\n        let (url, expected_sha256) = match &model_info.source {\n            ModelSource::Url { url, sha256 } => (url.clone(), sha256.clone()),\n            ModelSource::HuggingFace { repo_id, revision } => {\n                return self\n                    .download_hf_model(&model_info, repo_id.clone(), revision.clone())\n                    .await;\n            }\n            ModelSource::Local => {\n                return Err(anyhow::anyhow!(\"No download source for model\"));\n            }\n        };\n        let model_path = self.models_dir.join(&model_info.filename);\n        let partial_path = self\n            .models_dir\n            .join(format!(\"{}.partial\", &model_info.filename));\n\n        // Don't download if complete version already exists\n        if model_path.exists() {\n            // Clean up any partial file that might exist\n            if partial_path.exists() {\n                let _ = fs::remove_file(&partial_path);\n            }\n            self.update_download_status()?;\n            return Ok(());\n        }\n\n        // Mark as downloading","sourceCodeStart":2152,"sourceCodeEnd":2188,"githubUrl":"https://github.com/cjpais/Handy/blob/98a4d80cce8ad41efec2a419b59d9e81229a35d7/src-tauri/src/managers/model.rs#L2152-L2188","documentation":"download_model matched ModelSource::Local for the requested model. Local models are files the user imported or that were discovered on disk — they have no URL and no Hugging Face repo, so there is nothing to download by design.","triggerScenarios":"Calling download_model on a custom/imported or discovered-local model (is_custom or ModelSource::Local in the catalog); a UI that enables the download action for local entries.","commonSituations":"Frontend showing a generic download button for every list row; integrations assuming all models are downloadable; custom models created via 'add local model' flows.","solutions":["Guard the UI/action: hide or disable download for ModelSource::Local / is_custom entries","For local models, point the user to the model's own source to obtain the file manually"],"exampleFix":"// before\nmanager.download_model(&model.id).await?; // fires for local models\n\n// after\nif matches!(model.source, ModelSource::Local) {\n    return Ok(()); // nothing to download — skip instead of erroring\n}\nmanager.download_model(&model.id).await?;","handlingStrategy":"validation","validationCode":"match manager.get_model_info(model_id) {\n    Some(info) if matches!(info.source, ModelSource::Local) => {\n        // nothing to download — skip rather than error\n        return Ok(());\n    }\n    Some(_) => { /* safe to download */ }\n    None => anyhow::bail!(\"unknown model id {model_id}\"),\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Gate the download action on the model's source type in the UI","Treat is_custom / local models as non-downloadable everywhere the list is rendered"],"tags":["rust","model-manager","local-model","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"98a4d80cce8ad41efec2a419b59d9e81229a35d7","analyzedAt":"2026-08-16T20:58:09.966Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}