cjpais/Handy · error · anyhow::Error
error_msg (dynamic: model loading failure message)
Error message
error_msg (dynamic: model loading failure message)
What it means
In TranscriptionManager::load_model_with_device, when get_model_info(model_id) returns None the manager formats a dynamic "Model not found: <id>" message, emits a model-state-changed 'loading_failed' event so the frontend leaves its loading state, and returns this error via anyhow. It means the requested model_id does not correspond to any model known to the ModelManager.
Solutions
- Fix the model_id string: enumerate valid ids via the model manager's list/info API (or the model-selector UI) and use one of those exact ids.
- Reset or edit the persisted settings so they reference an existing model id, then reload.
- If the id comes from stored state after an app update, re-select the model in the UI to refresh the stored id.
- Wrap the load call and listen for the 'model-state-changed' loading_failed event in the frontend to recover UI state (the event is always emitted before this error propagates).
Example fix
// before
transcription.load_model("whisper-base-q5")?; // typo, no such id
// after
let id = model_manager.list_models()
.into_iter()
.find(|m| m.name.contains("Base"))
.map(|m| m.id)
.ok_or_else(|| anyhow::anyhow!("no suitable model installed"))?;
transcription.load_model(&id)?; Defensive patterns
Strategy: validation
Validate before calling
// Rust: verify the id exists before loading
if model_manager.get_model_info(model_id).is_none() {
return Err(anyhow::anyhow!("unknown model id: {}", model_id));
}
transcription.load_model(model_id)?;
// Frontend: check against the catalog first
const known = models.some(m => m.id === modelId);
if (!known) throw new Error(`unknown model id: ${modelId}`); Type guard
// Frontend narrowing: only pass ids from the typed catalog
function isKnownModelId(
id: string,
models: { id: string }[],
): id is string {
return models.some((m) => m.id === id);
} Try / catch
// Rust
if let Err(e) = transcription.load_model(model_id) {
log::error!("load failed: {e}");
// frontend also receives model-state-changed 'loading_failed' here
fallback_to_default_model()?;
}
// Frontend
listen('model-state-changed', (ev) => {
if (ev.payload.event_type === 'loading_failed') resetLoadingUi(ev.payload.error);
}); Prevention
- Never hardcode model id strings; always obtain ids from the model list/info API or generated bindings.
- After app updates, re-validate any model id persisted in settings against the current catalog before loading.
- Normalize/trim user-supplied ids and compare case-sensitively against the registry.
- Subscribe to the 'model-state-changed' loading_failed event so the UI never gets stuck when this error fires.
When it happens
Trigger: Calling load_model(model_id) or load_model_with_device(model_id, device) with an id that has no entry in the model registry: a typo'd/hardcoded id, an id from an older app version whose model list changed, a stale id persisted in settings or passed from the frontend before the model catalog initialized.
Common situations: Settings file or persisted store still references a model id removed/renamed after an app update; frontend sends an id from an outdated bindings/types list; third-party scripts invoking remote-control flags with an invalid model id; plugin/custom code constructing ids by hand instead of enumerating available models.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Device index ( ) cannot host a model
- error while building tauri application
- Failed to check macOS permissions:
- Failed to check Windows microphone permissions:
- Failed to check Windows microphone permissions:
AI-assisted analysis of cjpais/Handy@ba10ce1943 (2026-09-17).
Data as JSON: /api/errors/1619e1410c6600a4.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/managers/transcription.rs:514
model_name: None,
error: None,
},
);
let model_info = match self.model_manager.get_model_info(model_id) {
Some(model_info) => model_info,
None => {
let error_msg = format!("Model not found: {}", model_id);
let _ = self.app_handle.emit(
"model-state-changed",
ModelStateEvent {
event_type: "loading_failed".to_string(),
model_id: Some(model_id.to_string()),
model_name: None,
error: Some(error_msg.clone()),
},
);
return Err(anyhow::anyhow!(error_msg));
}
};
// Every failure after loading starts must emit a terminal event so the
// frontend can never remain in its loading state.
let emit_loading_failed = |error_msg: &str| {
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()),
},
);
};
if !model_info.is_downloaded {View on GitHub (pinned to ba10ce1943)