{"record":{"id":"036b2185cf4c6de0","repo":"cjpais/Handy","slug":"model-not-downloaded","errorCode":null,"errorMessage":"Model not downloaded","messagePattern":"Model not downloaded","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/src/managers/transcription.rs","lineNumber":517,"sourceCode":"        );\n\n        let model_info = self\n            .model_manager\n            .get_model_info(model_id)\n            .ok_or_else(|| anyhow::anyhow!(\"Model not found: {}\", model_id))?;\n\n        if !model_info.is_downloaded {\n            let error_msg = \"Model not downloaded\";\n            let _ = self.app_handle.emit(\n                \"model-state-changed\",\n                ModelStateEvent {\n                    event_type: \"loading_failed\".to_string(),\n                    model_id: Some(model_id.to_string()),\n                    model_name: Some(model_info.name.clone()),\n                    error: Some(error_msg.to_string()),\n                },\n            );\n            return Err(anyhow::anyhow!(error_msg));\n        }\n\n        let model_path = self.model_manager.get_model_path(model_id)?;\n\n        // Drop the current engine BEFORE building the new one so transcribe-cpp\n        // frees the previous native context first — avoids holding two models at\n        // once (peak memory on large GGUFs). Clear the id too: if the new load\n        // fails, status should read \"no loaded model\", not the dropped engine.\n        {\n            let mut engine = self.lock_engine();\n            *engine = None;\n        }\n        {\n            let mut current_model = self.current_model_id.lock().unwrap();\n            *current_model = None;\n        }\n\n        // Create appropriate engine based on model type","sourceCodeStart":499,"sourceCodeEnd":535,"githubUrl":"https://github.com/cjpais/Handy/blob/98a4d80cce8ad41efec2a419b59d9e81229a35d7/src-tauri/src/managers/transcription.rs#L499-L535","documentation":"The model exists in the catalog but its is_downloaded flag is false: no complete copy is registered on this machine. load_model emits a loading_failed 'model-state-changed' event carrying this message and aborts before ever calling get_model_path or touching the engine.","triggerScenarios":"The user or startup auto-load selects a model whose download never ran, failed, or was cancelled; the is_downloaded flag was reset after cache eviction; a load request raced the download start.","commonSituations":"Fresh installs where the preferred model download was skipped or interrupted; selecting an alternative model before it finishes downloading; state desync after files were removed externally.","solutions":["Call download_model(model_id) and wait for the completion event before loading","Pre-check get_model_info(model_id).is_downloaded and gate the load on it","If a previously downloaded model shows as not downloaded, run rescan_local_models to rebuild state from disk"],"exampleFix":"// before\nself.transcription_manager.load_model(model_id.clone()).await?;\n\n// after\nlet info = self.model_manager.get_model_info(&model_id)\n    .ok_or_else(|| anyhow::anyhow!(\"Model not found: {}\", model_id))?;\nif !info.is_downloaded {\n    self.model_manager.download_model(&model_id).await?; // wait for completion event\n}\nself.transcription_manager.load_model(model_id.clone()).await?;","handlingStrategy":"validation","validationCode":"let Some(info) = model_manager.get_model_info(model_id) else {\n    anyhow::bail!(\"Model not found: {}\", model_id);\n};\nif !info.is_downloaded {\n    model_manager.download_model(model_id).await?; // wait for completion event\n}","typeGuard":"fn is_model_downloadable(mm: &ModelManager, id: &str) -> bool {\n    mm.get_model_info(id).map(|i| i.is_downloaded).unwrap_or(false)\n}","tryCatchPattern":"match transcription_manager.load_model(model_id.clone()).await {\n    Ok(()) => Ok(()),\n    Err(e) if e.to_string() == \"Model not downloaded\" => {\n        // download then retry the load once\n        model_manager.download_model(&model_id).await?;\n        transcription_manager.load_model(model_id.clone()).await\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Gate the model selector on is_downloaded; show a download button instead of triggering load","After external cache changes, run rescan_local_models so is_downloaded reflects disk","On startup, if the active model is not downloaded, queue its download before use"],"tags":["model-download","state","transcription","prerequisite"],"backgroundTag":"model-not-downloaded","analyzedSha":"98a4d80cce8ad41efec2a419b59d9e81229a35d7","analyzedAt":"2026-08-16T20:58:09.966Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}