{"record":{"id":"8c481dd4618201b3","repo":"cjpais/Handy","slug":"model-not-found","errorCode":null,"errorMessage":"Model not found: {}","messagePattern":"Model not found: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/src/managers/model.rs","lineNumber":2160,"sourceCode":"            HttpDownloadOutcome::Completed => {\n                fs::rename(&partial_path, &model_path)?;\n                info!(\n                    \"Mirror download of {} completed and verified ({:?})\",\n                    model_id, model_path\n                );\n                Ok(true)\n            }\n        }\n    }\n\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","sourceCodeStart":2142,"sourceCodeEnd":2178,"githubUrl":"https://github.com/cjpais/Handy/blob/98a4d80cce8ad41efec2a419b59d9e81229a35d7/src-tauri/src/managers/model.rs#L2142-L2178","documentation":"download_model looked up model_id in the available_models map (catalog entries plus discovered/custom models) and found nothing. The id string is the single source of truth on both sides, so this is an id mismatch, not a download problem.","triggerScenarios":"UI list is stale (model removed by rescan or another window while a download request was queued); id typo; invoking with an id from a different app version or hand-written integration code.","commonSituations":"Race between a catalog rescan and a queued download; scripts/CLI driving the command layer with hardcoded ids after an update renamed entries; state desync between frontend model list and backend map.","solutions":["Re-fetch the model list (available models command) and use the exact id it returns","Check for trailing/leading whitespace or case differences in the id","If the list was modified concurrently, refresh the UI state before retrying"],"exampleFix":"// before\nmanager.download_model(model_id).await?;\n\n// after\nif manager.get_model_info(model_id).is_none() {\n    anyhow::bail!(\"unknown model id {model_id}; refresh the model list\");\n}\nmanager.download_model(model_id).await?;","handlingStrategy":"validation","validationCode":"if manager.get_model_info(model_id).is_none() {\n    anyhow::bail!(\"unknown model id {model_id} — refresh the available models list\");\n}\nmanager.download_model(model_id).await?;","typeGuard":null,"tryCatchPattern":"manager.download_model(model_id).await\n    .with_context(|| format!(\"download failed for id {model_id}; does it exist in the current model list?\"))?","preventionTips":["Pass ids straight from the model-list response — never hand-build them","Refresh the list after rescan/delete events before issuing downloads","Trim and case-normalize ids at the boundary"],"tags":["rust","model-manager","lookup","id-mismatch"],"backgroundTag":"model-not-found","analyzedSha":"98a4d80cce8ad41efec2a419b59d9e81229a35d7","analyzedAt":"2026-08-16T20:58:09.966Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}