cjpais/Handy · error · anyhow::Error

Complete model file not found in HF cache or models dir: {}

Error message

Complete model file not found in HF cache or models dir: {}

What it means

For a HuggingFace-sourced model, get_model_path first resolves the official HF cache via hf_cached_path(repo_id, revision, filename), then falls back to a manual drop-in under models_dir. This error means neither location holds the complete file even though the registry claims is_downloaded=true — the bookkeeping and the filesystem disagree. The stale .partial cleanup just above only runs when the local file does exist.

Source

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

        if let ModelSource::HuggingFace { repo_id, revision } = &model_info.source {
            if let Some(path) = hf_cached_path(repo_id, revision, &model_info.filename) {
                return Ok(path);
            }
            // Mirror-fallback download or manual drop-in in the models dir.
            // The complete file only ever appears after verification, so a
            // stale `.partial` alongside it is leftover noise, not a veto —
            // clear it rather than declaring the model missing.
            let local_path = self.models_dir.join(&model_info.filename);
            if local_path.exists() {
                let partial_path = self
                    .models_dir
                    .join(format!("{}.partial", &model_info.filename));
                if partial_path.exists() {
                    let _ = fs::remove_file(&partial_path);
                }
                return Ok(local_path);
            }
            return Err(anyhow::anyhow!(
                "Complete model file not found in HF cache or models dir: {}",
                model_id
            ));
        }

        let model_path = self.models_dir.join(&model_info.filename);
        let partial_path = self
            .models_dir
            .join(format!("{}.partial", &model_info.filename));

        if model_info.is_directory {
            // For directory-based models, ensure the directory exists and is complete
            if model_path.exists() && model_path.is_dir() && !partial_path.exists() {
                Ok(model_path)
            } else {
                Err(anyhow::anyhow!(
                    "Complete model directory not found: {}",
                    model_id

View on GitHub (pinned to 98a4d80cce)

Solutions

  1. Re-fetch the model: delete_model(model_id) then download_model(model_id)
  2. Check hf_cached_path inputs — repo_id/revision/filename must match the actual cache layout (snapshots/<revision>/<filename>)
  3. Restore or re-point the HF cache via HF_HOME to a location that still contains the snapshot
  4. For manual installs, place a file named exactly model_info.filename in the configured models_dir and run rescan_local_models

Example fix

// before
let path = self.model_manager.get_model_path(model_id)?;

// after — registry says downloaded but the bytes are gone: re-fetch
let path = match self.model_manager.get_model_path(model_id) {
    Ok(p) => p,
    Err(e) if self.model_manager.get_model_info(model_id)
        .map(|i| i.is_downloaded).unwrap_or(false) => {
        self.model_manager.delete_model(model_id)?;
        self.download_and_wait(model_id).await?;
        self.model_manager.get_model_path(model_id)?
    }
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: fallback

Validate before calling

let info = model_manager.get_model_info(model_id)
    .ok_or_else(|| anyhow::anyhow!("Model not found: {}", model_id))?;
if let ModelSource::HuggingFace { repo_id, revision } = &info.source {
    let cached = hf_cached_path(repo_id, revision, &info.filename);
    let local = model_manager.models_dir.join(&info.filename);
    if cached.is_none() && !local.exists() {
        // registry says downloaded but the file is gone — re-download now
        model_manager.delete_model(model_id)?;
        return re_download(model_id).await;
    }
}

Type guard

fn has_hf_model_bytes(
    mm: &ModelManager,
    repo_id: &str,
    revision: &str,
    filename: &str,
) -> bool {
    hf_cached_path(repo_id, revision, filename).is_some()
        || mm.models_dir.join(filename).exists()
}

Try / catch

match model_manager.get_model_path(model_id) {
    Ok(p) => Ok(p),
    Err(e) if e.to_string().contains("not found in HF cache") => {
        // bytes vanished despite is_downloaded=true: re-fetch as the fallback
        model_manager.delete_model(model_id)?;
        download_model_and_wait(model_id).await?;
        model_manager.get_model_path(model_id)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: The HF cache was evicted or cleared (huggingface-cli delete-cache, hf cache purge) while is_downloaded stayed true; HF_HOME/HF_ENDPOINT changed so hf_cached_path resolves elsewhere; models_dir moved or the drop-in file was deleted; the pinned revision snapshot no longer exists upstream.

Common situations: Users freeing disk space by deleting ~/.cache/huggingface; syncing settings to a new machine without syncing models; changing HF environment variables between runs; upstream repo deleting the pinned revision.

Related errors


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