cjpais/Handy · error · anyhow::Error
Model not downloaded
Error message
Model not downloaded
What it means
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.
Source
Thrown at src-tauri/src/managers/transcription.rs:517
);
let model_info = self
.model_manager
.get_model_info(model_id)
.ok_or_else(|| anyhow::anyhow!("Model not found: {}", model_id))?;
if !model_info.is_downloaded {
let error_msg = "Model not downloaded";
let _ = self.app_handle.emit(
"model-state-changed",
ModelStateEvent {
event_type: "loading_failed".to_string(),
model_id: Some(model_id.to_string()),
model_name: Some(model_info.name.clone()),
error: Some(error_msg.to_string()),
},
);
return Err(anyhow::anyhow!(error_msg));
}
let model_path = self.model_manager.get_model_path(model_id)?;
// Drop the current engine BEFORE building the new one so transcribe-cpp
// frees the previous native context first — avoids holding two models at
// once (peak memory on large GGUFs). Clear the id too: if the new load
// fails, status should read "no loaded model", not the dropped engine.
{
let mut engine = self.lock_engine();
*engine = None;
}
{
let mut current_model = self.current_model_id.lock().unwrap();
*current_model = None;
}
// Create appropriate engine based on model typeView on GitHub (pinned to 98a4d80cce)
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
Example fix
// before
self.transcription_manager.load_model(model_id.clone()).await?;
// after
let info = self.model_manager.get_model_info(&model_id)
.ok_or_else(|| anyhow::anyhow!("Model not found: {}", model_id))?;
if !info.is_downloaded {
self.model_manager.download_model(&model_id).await?; // wait for completion event
}
self.transcription_manager.load_model(model_id.clone()).await?; Defensive patterns
Strategy: validation
Validate before calling
let Some(info) = model_manager.get_model_info(model_id) else {
anyhow::bail!("Model not found: {}", model_id);
};
if !info.is_downloaded {
model_manager.download_model(model_id).await?; // wait for completion event
} Type guard
fn is_model_downloadable(mm: &ModelManager, id: &str) -> bool {
mm.get_model_info(id).map(|i| i.is_downloaded).unwrap_or(false)
} Try / catch
match transcription_manager.load_model(model_id.clone()).await {
Ok(()) => Ok(()),
Err(e) if e.to_string() == "Model not downloaded" => {
// download then retry the load once
model_manager.download_model(&model_id).await?;
transcription_manager.load_model(model_id.clone()).await
}
Err(e) => Err(e),
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Model is not loaded for transcription.
- Model failed to load after auto-load attempt. Please check y
- Model is currently downloading: {}
- Complete model file not found in HF cache or models dir: {}
- Complete model directory not found: {}
AI-assisted analysis of cjpais/Handy@98a4d80cce (2026-08-16).
Data as JSON: /api/errors/036b2185cf4c6de0.
Report an issue: GitHub.