{"record":{"id":"e9e250389cbf8141","repo":"Zackriya-Solutions/meetily","slug":"can-only-delete-corrupted-or-available-parakeet-mo","errorCode":null,"errorMessage":"Can only delete corrupted or available Parakeet models. Model '{}' has status: {:?}","messagePattern":"Can only delete corrupted or available Parakeet models\\. Model '(.+?)' has status: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"frontend/src-tauri/src/parakeet_engine/parakeet_engine.rs","lineNumber":519,"sourceCode":"                    fs::remove_dir_all(&model_info.path).await\n                        .map_err(|e| anyhow!(\"Failed to delete directory '{}': {}\", model_info.path.display(), e))?;\n                    log::info!(\"Successfully deleted Parakeet model directory: {}\", model_info.path.display());\n                } else {\n                    log::warn!(\"Directory '{}' 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 Parakeet model '{}'\", model_name))\n            }\n            _ => {\n                Err(anyhow!(\n                    \"Can only delete corrupted or available Parakeet models. Model '{}' has status: {:?}\",\n                    model_name,\n                    model_info.status\n                ))\n            }\n        }\n    }\n\n    /// Download a Parakeet model from HuggingFace (backward-compatible wrapper)\n    pub async fn download_model(\n        &self,\n        model_name: &str,\n        progress_callback: Option<Box<dyn Fn(u8) + Send>>,\n    ) -> Result<()> {\n        // Wrap simple callback to use detailed version\n        let detailed_callback: Option<Box<dyn Fn(DownloadProgress) + Send>> =\n            progress_callback.map(|cb| {\n                Box::new(move |p: DownloadProgress| cb(p.percent)) as Box<dyn Fn(DownloadProgress) + Send>","sourceCodeStart":501,"sourceCodeEnd":537,"githubUrl":"https://github.com/Zackriya-Solutions/meetily/blob/0281737d87d26352fb0adc78c8c0975f691b23d1/frontend/src-tauri/src/parakeet_engine/parakeet_engine.rs#L501-L537","documentation":"Returned by delete_model for any status other than Corrupted or Available. The match arm intentionally refuses to delete models that are Missing (nothing on disk to remove), Downloading (an active task is writing files), or Error (not in a deletable state per this state machine), so the status enum value is echoed back in the message.","triggerScenarios":"Calling delete_model while download_model_detailed is streaming for that model (status Downloading); calling delete on a model already deleted/reset to Missing; calling delete on a model stuck in Error status expecting cleanup.","commonSituations":"User hits 'delete' on a model row whose download is still running; double-delete after a failed download left status Missing; UI delete button enabled for all rows regardless of state.","solutions":["If Downloading: call parakeet_cancel_download / engine.cancel_download first, wait for the task to unwind, then delete (files will be gone or deletable)","If Missing: nothing to delete - refresh the model list; the row should show as not downloaded","If Error: re-attempt the download once so status transitions, or restart the app to re-discover, then delete","Gate the delete button in the UI on status being Available or Corrupted"],"exampleFix":"// before\nengine.delete_model(name).await?;\n\n// after - only delete in a deletable state, cancel active downloads first\nlet status = engine.discover_models().await?\n    .into_iter().find(|m| m.name == name).map(|m| m.status);\nmatch status {\n    Some(ModelStatus::Downloading { .. }) => { engine.cancel_download(&name).await?; }\n    Some(ModelStatus::Corrupted { .. }) | Some(ModelStatus::Available) => {\n        engine.delete_model(&name).await?;\n    }\n    _ => { /* nothing deletable */ }\n}","handlingStrategy":"validation","validationCode":"// Only offer deletion in states that support it; cancel active downloads first\nlet status = engine.discover_models().await?\n    .into_iter().find(|m| m.name == name).map(|m| m.status);\nmatch status {\n    Some(ModelStatus::Downloading { .. }) => engine.cancel_download(&name).await?,\n    Some(ModelStatus::Available) | Some(ModelStatus::Corrupted { .. }) => { /* safe to delete */ }\n    other => anyhow::bail!(\"not deletable in state {other:?}\"),\n}","typeGuard":"fn is_deletable(info: &ModelInfo) -> bool {\n    matches!(info.status, ModelStatus::Available | ModelStatus::Corrupted { .. })\n}","tryCatchPattern":"try {\n  await invoke('parakeet_delete_corrupted_model', { modelName });\n} catch (e) {\n  if (String(e).includes('Can only delete')) {\n    // state problem, not a failure: cancel download or refresh list, never blind-retry\n  } else {\n    throw e;\n  }\n}","preventionTips":["Enable the delete button only when status is Available or Corrupted","Cancel a running download before offering delete of the same model","Treat Missing as 'nothing to delete' and refresh the row"],"tags":["parakeet","state-machine","model-management","download"],"backgroundTag":"invalid-state-transition","analyzedSha":"0281737d87d26352fb0adc78c8c0975f691b23d1","analyzedAt":"2026-08-16T20:57:52.567Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}