{"record":{"id":"9c624463d3619dd8","repo":"cjpais/Handy","slug":"no-model-files-found-to-delete","errorCode":null,"errorMessage":"No model files found to delete","messagePattern":"No model files found to delete","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"src-tauri/src/managers/model.rs","lineNumber":2418,"sourceCode":"                        deleted = true;\n                    }\n                }\n            }\n            // Also remove a models-dir copy (mirror fallback / manual drop-in)\n            // and any resumable partial next to it.\n            for path in [\n                self.models_dir.join(&model_info.filename),\n                self.models_dir\n                    .join(format!(\"{}.partial\", &model_info.filename)),\n            ] {\n                if path.exists() {\n                    info!(\"Deleting model file at: {:?}\", path);\n                    fs::remove_file(&path)?;\n                    deleted = true;\n                }\n            }\n            if !deleted {\n                return Err(anyhow::anyhow!(\"No model files found to delete\"));\n            }\n            // Alternate-quant entries are discovery-created (the catalog only\n            // seeds defaults), so deleting one un-discovers it rather than\n            // leaving a permanent \"(Q4_K_M)\" row in the list.\n            if is_alternate_quant {\n                self.available_models.lock().unwrap().remove(model_id);\n            }\n            self.update_download_status()?;\n            let _ = self.app_handle.emit(\"model-deleted\", model_id);\n            return Ok(());\n        }\n\n        let model_path = self.models_dir.join(&model_info.filename);\n        let partial_path = self\n            .models_dir\n            .join(format!(\"{}.partial\", &model_info.filename));\n        debug!(\"ModelManager: Model path: {:?}\", model_path);\n        debug!(\"ModelManager: Partial path: {:?}\", partial_path);","sourceCodeStart":2400,"sourceCodeEnd":2436,"githubUrl":"https://github.com/cjpais/Handy/blob/fbd4e15fa14a721c66c57006ae110428b9e255b3/src-tauri/src/managers/model.rs#L2400-L2436","documentation":"Delete was requested for an HF-sourced model, but neither the HF cache blob/snapshot file (including the alternate-quant single-file path) nor the model file in models_dir existed — so nothing was deleted and the operation reports that instead of silently succeeding. The HF branch deletes per-quant files (snapshot pointer + blob) so an externally emptied cache ends here.","triggerScenarios":"Double-delete: a prior delete already removed the blob; user cleared the HF cache externally (huggingface-cli delete-cache or manual rm of ~/.cache/huggingface); is_downloaded flag was stale (cache emptied while app was running).","commonSituations":"Users reclaiming disk space by wiping the HF cache while the app still lists the model; two delete requests racing; app data migrated between machines without the cache.","solutions":["Treat as harmless in practice — refresh/restart so download status resyncs with disk","If the UI still shows the model as downloaded, restart the app to rebuild is_downloaded flags","As a maintainer: make delete idempotent by treating 'nothing to delete' as success when the goal is removal"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// check the HF cache blob and local file before asking for a delete\nlet exists = hf_cached_path(&repo_id, &revision, &filename).is_some()\n    || self.models_dir.join(&filename).exists();\nif !exists {\n    // nothing on disk — just resync status instead of erroring\n    self.update_download_status()?;\n    return Ok(());\n}","typeGuard":null,"tryCatchPattern":"match manager.delete_model(id) {\n    Err(e) if e.to_string().contains(\"No model files found\") => {\n        // already gone externally — treat as success, refresh status\n        manager.update_download_status()?;\n        Ok(())\n    }\n    other => other,\n}?","preventionTips":["Make delete idempotent at the command layer: missing files should succeed, not error","Resync download status from disk (update_download_status) after cache wipes instead of trusting flags"],"tags":["rust","model","delete","huggingface","idempotency"],"backgroundTag":"delete-target-missing","analyzedSha":"fbd4e15fa14a721c66c57006ae110428b9e255b3","analyzedAt":"2026-08-17T10:29:55.597Z","contentChangedAt":"2026-08-17T10:29:55.597Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}