cjpais/Handy · error · anyhow::Error
Model not found
Error message
Model not found: {} What it means
Raised by the transcription engine's load_model flow when ModelManager::get_model_info(model_id) returns None — the id is not present in the model catalog at all. This is an id-resolution failure, distinct from a download-state failure: the model was never registered (or the catalog changed under the caller). A 'loading_failed' model-state-changed event is not even emitted for this branch; the error is returned directly.
Solutions
- List available models (model manager list / model-selector UI) and use an id from that list.
- If settings reference the dead id, pick a current model in the UI so the setting is re-persisted.
- Update the app so frontend bindings and backend catalog agree.
- Check for exact-match pitfalls: ids are case-sensitive strings, not display names.
Example fix
// before
let info = self.model_manager.get_model_info(model_id)
.ok_or_else(|| anyhow::anyhow!("Model not found: {}", model_id))?;
// after — include the valid ids in the error so the caller can self-correct
let info = self.model_manager.get_model_info(model_id).ok_or_else(|| {
let known: Vec<_> = self.model_manager.list_models().iter().map(|m| m.id.clone()).collect();
anyhow::anyhow!("Model not found: {} (known: {:?})", model_id, known)
})?; Defensive patterns
Strategy: validation
Validate before calling
// Resolve the id against the live catalog before starting the load
let known_ids: Vec<String> = model_manager.list_models().iter().map(|m| m.id.clone()).collect();
if !known_ids.contains(&model_id.to_string()) {
anyhow::bail!("model id '{model_id}' not in catalog; valid ids: {known_ids:?}");
} Type guard
fn is_known_model_id(id: &str, catalog: &[ModelInfo]) -> bool {
catalog.iter().any(|m| m.id == id)
} Try / catch
match manager.load_model(model_id).await {
Ok(_) => Ok(()),
Err(e) if e.to_string().starts_with("Model not found") => {
// stale id in settings: refresh catalog, prompt user to re-pick
refresh_catalog();
Err(e)
}
Err(e) => Err(e),
} Prevention
- Drive model selection UI from the live catalog so users can only pick valid ids.
- On settings load, validate persisted model ids against the current catalog and reset to a default if gone.
- Treat model ids as opaque, case-sensitive strings — never reconstruct them from names.
When it happens
Trigger: Calling load_model with a model_id that is misspelled, removed in the current catalog, or produced by a stale settings file/frontend referencing an older model list.
Common situations: Persisted settings from an older app version pointing at a model id that no longer exists; hand-edited config; frontend/backend version skew after a partial update; scripts invoking the load command with guessed ids.
Related errors
- Model not available
- Model not downloaded
- Complete model directory not found
- Complete model file not found
- download incomplete: expected
AI-assisted analysis of cjpais/Handy@fbd4e15fa1 (2026-08-17).
Data as JSON: /api/errors/bb30d03c4c33ec35.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/managers/transcription.rs:504
let load_start = std::time::Instant::now();
debug!("Starting to load model: {}", model_id);
// Emit loading started event
let _ = self.app_handle.emit(
"model-state-changed",
ModelStateEvent {
event_type: "loading_started".to_string(),
model_id: Some(model_id.to_string()),
model_name: None,
error: None,
},
);
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-cppView on GitHub (pinned to fbd4e15fa1)