cjpais/Handy · error · anyhow::Error
Model file is incomplete
Error message
Model file is incomplete: {} What it means
Thrown by ModelManager::get_model_path for single-file models (is_directory == false): the model file exists in the models directory, but a companion `<filename>.partial` file is also present. `.partial` is the in-progress download artifact and is only removed once the download completes and is verified, so its presence marks the model as not fully downloaded/verified and the manager will not return the path.
Solutions
- Delete the stale `<model_filename>.partial` file from the models directory, then retry get_model_path.
- If the main file itself may be truncated, delete both files and re-download the model through the app.
- Trigger a fresh download in the app (which will resume/redo and clean the marker) instead of hand-editing the models dir.
- Verify the download is not currently in progress before deleting anything.
Example fix
// before: interrupted download left the marker ls models_dir # ggml-base.bin ggml-base.bin.partial rm models_dir/ggml-base.bin.partial // after: get_model_path returns models_dir/ggml-base.bin
Defensive patterns
Strategy: validation
Validate before calling
use std::path::Path;
fn model_file_complete(models_dir: &Path, filename: &str) -> bool {
models_dir.join(filename).is_file()
&& !models_dir.join(format!("{}.partial", filename)).exists()
}
// if false, delete the .partial (and re-verify the file) before calling load Type guard
fn is_complete_model_file(p: &Path) -> bool {
p.is_file() && !p.with_file_name(format!("{}.partial", p.file_name().map(|s| s.to_string_lossy().to_string()).unwrap_or_default())).exists()
} Try / catch
match manager.get_model_path(id) {
Ok(p) => p,
Err(e) if e.to_string().contains("incomplete") => {
let partial = models_dir.join(format!("{}.partial", filename));
let _ = std::fs::remove_file(&partial);
manager.get_model_path(id).context("model file still incomplete")?
}
Err(e) => return Err(e),
} Prevention
- Check is_downloaded / is_downloading in model info before attempting to load.
- Use the app's download/cancel flow instead of manually placing files in the models dir; if you must drop files in manually, remove any leftover .partial first.
- Avoid interrupting downloads (sleep, shutdown, disk-full); monitor free disk space for large GGUF downloads.
- Periodically clean *.partial leftovers from the models directory after abnormal exits.
When it happens
Trigger: Calling get_model_path(model_id) (directly or through load_model / load_model_with_device) for a file-based model when: (1) a prior download was interrupted (app crash, SIGKILL, power loss, disk full) leaving `<file>.partial` on disk; (2) a manual drop-in of the model file was done while an old `.partial` file remained; (3) the app's is_downloaded flag is stale relative to the actual files on disk.
Common situations: User kills the app during a large GGUF download; laptop sleeps/dies mid-download; cloud-sync (Dropbox/iCloud) restores a `.partial` file together with the model; user manually downloads a model from a mirror and drops it in the models dir while a leftover partial from a failed attempt remains.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- Model directory is incomplete
- Complete model file not found
- error_msg (dynamic: model loading failure message)
- Failed to initialize model manager
- Failed to initialize store
AI-assisted analysis of cjpais/Handy@ba10ce1943 (2026-09-17).
Data as JSON: /api/errors/60eabebdbccdac69.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/managers/model.rs:2633
));
}
if partial_path.exists() {
return Err(anyhow::anyhow!(
"Model directory is incomplete: {}",
model_id
));
}
Ok(model_path)
} else {
if !model_path.exists() {
self.mark_model_unavailable(model_id);
return Err(anyhow::anyhow!(
"Complete model file not found: {}",
model_id
));
}
if partial_path.exists() {
return Err(anyhow::anyhow!("Model file is incomplete: {}", model_id));
}
Ok(model_path)
}
}
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);
} else {
warn!("No active download found for: {}", model_id);View on GitHub (pinned to ba10ce1943)