cjpais/Handy · error · anyhow::Error
Complete model file not found
Error message
Complete model file not found: {} What it means
Returned by ModelManager::get_model_path() for file-based models when neither a complete model file nor a state without a matching .partial download exists — i.e., there is nothing on disk to load for the given model_id. It is the 'the model you asked for is not present locally' error. Directory-based models have a sibling 'Complete model directory not found' variant just above.
Solutions
- Download the model first via the model manager / model-selector UI before requesting its path.
- Check is_downloaded (or list models) to confirm on-disk state instead of assuming the catalog reflects disk.
- If a .partial file lingers from an interrupted download, resume or restart the download — do not delete the partial if resume is desired.
- Verify the app's model data directory was not moved or cleaned by an external tool (disk cleaners are a common culprit).
Example fix
// before
let path = model_manager.get_model_path(model_id)?;
// after — gate on download state and recover
if !model_manager.get_model_info(model_id).map(|i| i.is_downloaded).unwrap_or(false) {
model_manager.download_model(model_id, None).await?;
}
let path = model_manager.get_model_path(model_id)?; Defensive patterns
Strategy: validation
Validate before calling
// Check on-disk state before asking for a path
let info = model_manager.get_model_info(model_id)
.ok_or_else(|| anyhow::anyhow!("unknown model id {model_id}"))?;
if !info.is_downloaded {
model_manager.download_model(model_id, None).await?;
}
let path = model_manager.get_model_path(model_id)?; Type guard
fn model_is_ready(m: &ModelInfo) -> bool {
m.is_downloaded // catalog flag mirrors a verified on-disk file
} Try / catch
match model_manager.get_model_path(model_id) {
Ok(p) => p,
Err(e) if e.to_string().contains("Complete model") => {
// nothing on disk: download then retry
model_manager.download_model(model_id, None).await?;
model_manager.get_model_path(model_id)?
}
Err(e) => return Err(e),
} Prevention
- Always gate load on is_downloaded, never on catalog presence alone.
- Do not delete or move files under the models directory manually; use the app's remove-model flow.
- Treat a lingering .partial as 'download in progress or interrupted' — resume it rather than assuming a complete model.
- After external disk cleanup, trigger a state refresh before loading.
When it happens
Trigger: Calling get_model_path(model_id) when the model was never downloaded, a previous download left only a .partial file, the models directory was moved/cleaned, or files were deleted externally while the catalog still marks the model as downloaded.
Common situations: Asking transcription to load a model right after a fresh install without downloading; users clearing app data / model cache folders; a download interrupted by app exit leaving only partial files; settings pointing at a model removed in a newer catalog.
Related errors
- download incomplete: expected
- Download verification failed for model
- Model is currently downloading
- server object ends before the expected size (HTTP 416)
- Complete model directory not found
AI-assisted analysis of cjpais/Handy@ba10ce1943 (2026-09-17).
Data as JSON: /api/errors/26c78c9520e1dd3a.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/managers/model.rs:2627
if model_info.is_directory {
if !model_path.exists() || !model_path.is_dir() {
self.mark_model_unavailable(model_id);
return Err(anyhow::anyhow!(
"Complete model directory not found: {}",
model_id
));
}
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.
{View on GitHub (pinned to ba10ce1943)