cjpais/Handy · error · anyhow::Error

Model not found: {}

Error message

Model not found: {}

What it means

download_model looked up model_id in the available_models map (catalog entries plus discovered/custom models) and found nothing. The id string is the single source of truth on both sides, so this is an id mismatch, not a download problem.

Source

Thrown at src-tauri/src/managers/model.rs:2160

            HttpDownloadOutcome::Completed => {
                fs::rename(&partial_path, &model_path)?;
                info!(
                    "Mirror download of {} completed and verified ({:?})",
                    model_id, model_path
                );
                Ok(true)
            }
        }
    }

    pub async fn download_model(&self, model_id: &str) -> Result<()> {
        let model_info = {
            let models = self.available_models.lock().unwrap();
            models.get(model_id).cloned()
        };

        let model_info =
            model_info.ok_or_else(|| anyhow::anyhow!("Model not found: {}", model_id))?;

        let (url, expected_sha256) = match &model_info.source {
            ModelSource::Url { url, sha256 } => (url.clone(), sha256.clone()),
            ModelSource::HuggingFace { repo_id, revision } => {
                return self
                    .download_hf_model(&model_info, repo_id.clone(), revision.clone())
                    .await;
            }
            ModelSource::Local => {
                return Err(anyhow::anyhow!("No download source for model"));
            }
        };
        let model_path = self.models_dir.join(&model_info.filename);
        let partial_path = self
            .models_dir
            .join(format!("{}.partial", &model_info.filename));

        // Don't download if complete version already exists

View on GitHub (pinned to 98a4d80cce)

Solutions

  1. Re-fetch the model list (available models command) and use the exact id it returns
  2. Check for trailing/leading whitespace or case differences in the id
  3. If the list was modified concurrently, refresh the UI state before retrying

Example fix

// before
manager.download_model(model_id).await?;

// after
if manager.get_model_info(model_id).is_none() {
    anyhow::bail!("unknown model id {model_id}; refresh the model list");
}
manager.download_model(model_id).await?;
Defensive patterns

Strategy: validation

Validate before calling

if manager.get_model_info(model_id).is_none() {
    anyhow::bail!("unknown model id {model_id} — refresh the available models list");
}
manager.download_model(model_id).await?;

Try / catch

manager.download_model(model_id).await
    .with_context(|| format!("download failed for id {model_id}; does it exist in the current model list?"))?

Prevention

When it happens

Trigger: UI list is stale (model removed by rescan or another window while a download request was queued); id typo; invoking with an id from a different app version or hand-written integration code.

Common situations: Race between a catalog rescan and a queued download; scripts/CLI driving the command layer with hardcoded ids after an update renamed entries; state desync between frontend model list and backend map.

Related errors


AI-assisted analysis of cjpais/Handy@98a4d80cce (2026-08-16). Data as JSON: /api/errors/8c481dd4618201b3. Report an issue: GitHub.