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

  1. List available models (model manager list / model-selector UI) and use an id from that list.
  2. If settings reference the dead id, pick a current model in the UI so the setting is re-persisted.
  3. Update the app so frontend bindings and backend catalog agree.
  4. 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

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


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-cpp

View on GitHub (pinned to fbd4e15fa1)