{"record":{"id":"06ea8214b1480955","repo":"Zackriya-Solutions/meetily","slug":"can-only-delete-corrupted-or-available-models-mod","errorCode":null,"errorMessage":"Can only delete corrupted or available models. Model '{}' has status: {:?}","messagePattern":"Can only delete corrupted or available models\\. Model '(.+?)' has status: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"frontend/src-tauri/src/whisper_engine/whisper_engine.rs","lineNumber":927,"sourceCode":"                    fs::remove_file(&model_info.path).await\n                        .map_err(|e| anyhow!(\"Failed to delete file '{}': {}\", model_info.path.display(), e))?;\n                    log::info!(\"Successfully deleted available model file: {}\", model_info.path.display());\n                } else {\n                    log::warn!(\"File '{}' does not exist, nothing to delete\", model_info.path.display());\n                }\n\n                // Update model status to Missing\n                {\n                    let mut models = self.available_models.write().await;\n                    if let Some(model) = models.get_mut(model_name) {\n                        model.status = ModelStatus::Missing;\n                    }\n                }\n\n                Ok(format!(\"Successfully deleted model '{}'\", model_name))\n            }\n            _ => {\n                Err(anyhow!(\"Can only delete corrupted or available models. Model '{}' has status: {:?}\", model_name, model_info.status))\n            }\n        }\n    }\n    \n    async fn reserve_active_download(&self, model_name: &str) -> Result<Arc<ActiveDownload>> {\n        let mut active_downloads = self.active_downloads.lock().await;\n        if active_downloads.contains_key(model_name) {\n            return Err(anyhow!(\"Download already in progress for model: {}\", model_name));\n        }\n\n        let (completion, _) = watch::channel(false);\n        let active_download = Arc::new(ActiveDownload {\n            cancellation: CancellationToken::new(),\n            completion,\n        });\n\n        active_downloads.insert(model_name.to_string(), Arc::clone(&active_download));\n        Ok(active_download)","sourceCodeStart":909,"sourceCodeEnd":945,"githubUrl":"https://github.com/Zackriya-Solutions/meetily/blob/a2cb62e827da7ef59f65064c97233efb2313878e/frontend/src-tauri/src/whisper_engine/whisper_engine.rs#L909-L945","documentation":"delete_model only handles ModelStatus::Corrupted and ModelStatus::Available; every other status falls to the catch-all arm and is rejected with the current status shown. This is a deliberate state-machine guard: you cannot delete what is Missing (nothing on disk), Downloading (an active task owns the file), or Error (recover by re-downloading instead).","triggerScenarios":"Calling delete_model while download_model streams the same model (Downloading); double-delete where the first call already set status Missing; calling delete on a model whose status is Error.","commonSituations":"User hits Delete during an active download; UI row not refreshed after a delete so the action fires twice; trying to 'clear' an Error state by deleting it.","solutions":["For Downloading: cancel the download first (set the cancel flag / cancel_download command) or wait for it to finish, then delete","For Missing: nothing to delete — refresh the model list; the action already succeeded earlier","For Error: re-run download_model to overwrite the bad file instead of deleting, or remove the file manually and rescan"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const models = await invoke<ModelInfo[]>('get_whisper_models');\nconst m = models.find(x => x.name === modelName);\nif (!m) throw new Error('Unknown model');\nif (m.status !== 'Available' && m.status !== 'Corrupted') {\n  throw new Error(`Cannot delete while status is ${m.status}. Cancel the download or refresh.`);\n}\nawait invoke('delete_model', { modelName });","typeGuard":"const isDeletable = (s: string): boolean => s === 'Available' || s === 'Corrupted';","tryCatchPattern":"try {\n  await invoke('delete_model', { modelName });\n} catch (e) {\n  if (String(e).includes('Can only delete')) {\n    // Downloading -> cancel first; Missing -> refresh list; Error -> re-download instead\n    refreshModelList();\n  } else { throw e; }\n}","preventionTips":["Hide or disable Delete for rows whose status is not Available/Corrupted","Cancel an active download before offering deletion of the same model","Refresh the model list after every delete/cancel to prevent stale-row double actions"],"tags":["whisper","model-management","state-machine","rust"],"backgroundTag":"invalid-state-transition","analyzedSha":"a2cb62e827da7ef59f65064c97233efb2313878e","analyzedAt":"2026-08-16T20:57:52.567Z","contentChangedAt":"2026-08-16T20:57:52.567Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}