cjpais/Handy · error · anyhow::Error

Complete model file not found: {}

Error message

Complete model file not found: {}

What it means

For file-based (non-HF) models, get_model_path returns models_dir/<filename> only when that file exists and no <filename>.partial sits alongside it (the .partial proves an unfinished transfer). This error means the target file is missing or a partial marker taints it.

Source

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

            .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
                ))
            }
        } else {
            // For file-based models (existing logic)
            if model_path.exists() && !partial_path.exists() {
                Ok(model_path)
            } else {
                Err(anyhow::anyhow!(
                    "Complete model file not found: {}",
                    model_id
                ))
            }
        }
    }

    pub fn cancel_download(&self, model_id: &str) -> Result<()> {
        debug!("ModelManager: cancel_download called for: {}", model_id);

        // Trigger the cancellation token to stop the download. The HF path
        // aborts its in-flight chunk tasks and unwinds promptly; the URL path
        // observes it on the next chunk of its stream loop.
        {
            let flags = self.cancel_flags.lock().unwrap();
            if let Some(token) = flags.get(model_id) {
                token.cancel();
                info!("Cancellation token triggered for: {}", model_id);

View on GitHub (pinned to 98a4d80cce)

Solutions

  1. Remove the stale <filename>.partial marker if the target file is verifiably complete, then retry
  2. Re-download via delete_model(model_id) + download_model(model_id) to obtain a hash-verified complete file
  3. Confirm the file name matches model_info.filename exactly (no .partial suffix, no rename) inside models_dir
Defensive patterns

Strategy: validation

Validate before calling

let Some(info) = model_manager.get_model_info(model_id) else {
    anyhow::bail!("Model not found: {}", model_id);
};
if !info.is_directory {
    let file = model_manager.models_dir.join(&info.filename);
    let partial = model_manager.models_dir.join(format!("{}.partial", info.filename));
    if !(file.is_file() && !partial.exists()) {
        return re_download(model_id).await;
    }
}

Type guard

fn file_model_complete(mm: &ModelManager, filename: &str) -> bool {
    let file = mm.models_dir.join(filename);
    let partial = mm.models_dir.join(format!("{}.partial", filename));
    file.is_file() && !partial.exists()
}

Try / catch

match model_manager.get_model_path(model_id) {
    Ok(p) => Ok(p),
    Err(e) if e.to_string().starts_with("Complete model file not found") => {
        // file missing or tainted by a .partial marker: re-download verified bytes
        download_model_and_wait(model_id).await?;
        model_manager.get_model_path(model_id)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: An interrupted download left <filename>.partial next to a missing/incomplete target; the GGUF/ONNX file was deleted, moved, or renamed after being marked downloaded; models_dir location changed.

Common situations: Killing the app mid-download; antivirus quarantining a large model file; users manually cleaning the models folder; restoring settings on a new machine without the model files.

Related errors


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