{"record":{"id":"60eabebdbccdac69","repo":"cjpais/Handy","slug":"model-file-is-incomplete","errorCode":null,"errorMessage":"Model file is incomplete: {}","messagePattern":"Model file is incomplete: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/src/managers/model.rs","lineNumber":2633,"sourceCode":"                ));\n            }\n            if partial_path.exists() {\n                return Err(anyhow::anyhow!(\n                    \"Model directory is incomplete: {}\",\n                    model_id\n                ));\n            }\n            Ok(model_path)\n        } else {\n            if !model_path.exists() {\n                self.mark_model_unavailable(model_id);\n                return Err(anyhow::anyhow!(\n                    \"Complete model file not found: {}\",\n                    model_id\n                ));\n            }\n            if partial_path.exists() {\n                return Err(anyhow::anyhow!(\"Model file is incomplete: {}\", model_id));\n            }\n            Ok(model_path)\n        }\n    }\n\n    pub fn cancel_download(&self, model_id: &str) -> Result<()> {\n        debug!(\"ModelManager: cancel_download called for: {}\", model_id);\n\n        // Trigger the cancellation token to stop the download. The HF path\n        // aborts its in-flight chunk tasks and unwinds promptly; the URL path\n        // observes it on the next chunk of its stream loop.\n        {\n            let flags = self.cancel_flags.lock().unwrap();\n            if let Some(token) = flags.get(model_id) {\n                token.cancel();\n                info!(\"Cancellation token triggered for: {}\", model_id);\n            } else {\n                warn!(\"No active download found for: {}\", model_id);","sourceCodeStart":2615,"sourceCodeEnd":2651,"githubUrl":"https://github.com/cjpais/Handy/blob/ba10ce1943ef34e93c09494027fc0b9ced2e8a44/src-tauri/src/managers/model.rs#L2615-L2651","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: interrupted download left the marker\nls models_dir\n# ggml-base.bin  ggml-base.bin.partial\nrm models_dir/ggml-base.bin.partial\n// after: get_model_path returns models_dir/ggml-base.bin","handlingStrategy":"validation","validationCode":"use std::path::Path;\nfn model_file_complete(models_dir: &Path, filename: &str) -> bool {\n    models_dir.join(filename).is_file()\n        && !models_dir.join(format!(\"{}.partial\", filename)).exists()\n}\n// if false, delete the .partial (and re-verify the file) before calling load","typeGuard":"fn is_complete_model_file(p: &Path) -> bool {\n    p.is_file() && !p.with_file_name(format!(\"{}.partial\", p.file_name().map(|s| s.to_string_lossy().to_string()).unwrap_or_default())).exists()\n}","tryCatchPattern":"match manager.get_model_path(id) {\n    Ok(p) => p,\n    Err(e) if e.to_string().contains(\"incomplete\") => {\n        let partial = models_dir.join(format!(\"{}.partial\", filename));\n        let _ = std::fs::remove_file(&partial);\n        manager.get_model_path(id).context(\"model file still incomplete\")?\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["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."],"tags":["model-management","download-incomplete","filesystem","stale-state"],"backgroundTag":"file-already-exists","analyzedSha":"ba10ce1943ef34e93c09494027fc0b9ced2e8a44","analyzedAt":"2026-09-17T15:09:05.215Z","contentChangedAt":"2026-09-17T15:09:05.215Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}