Zackriya-Solutions/meetily · warning · anyhow::Error

Can only delete corrupted or available Parakeet models…

Error message

Can only delete corrupted or available Parakeet models. Model '{}' has status: {:?}

What it means

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.

Solutions

  1. If Downloading: call parakeet_cancel_download / engine.cancel_download first, wait for the task to unwind, then delete (files will be gone or deletable)
  2. If Missing: nothing to delete - refresh the model list; the row should show as not downloaded
  3. If Error: re-attempt the download once so status transitions, or restart the app to re-discover, then delete
  4. Gate the delete button in the UI on status being Available or Corrupted

Example fix

// before
engine.delete_model(name).await?;

// after - only delete in a deletable state, cancel active downloads first
let status = engine.discover_models().await?
    .into_iter().find(|m| m.name == name).map(|m| m.status);
match status {
    Some(ModelStatus::Downloading { .. }) => { engine.cancel_download(&name).await?; }
    Some(ModelStatus::Corrupted { .. }) | Some(ModelStatus::Available) => {
        engine.delete_model(&name).await?;
    }
    _ => { /* nothing deletable */ }
}
Defensive patterns

Strategy: validation

Validate before calling

// Only offer deletion in states that support it; cancel active downloads first
let status = engine.discover_models().await?
    .into_iter().find(|m| m.name == name).map(|m| m.status);
match status {
    Some(ModelStatus::Downloading { .. }) => engine.cancel_download(&name).await?,
    Some(ModelStatus::Available) | Some(ModelStatus::Corrupted { .. }) => { /* safe to delete */ }
    other => anyhow::bail!("not deletable in state {other:?}"),
}

Type guard

fn is_deletable(info: &ModelInfo) -> bool {
    matches!(info.status, ModelStatus::Available | ModelStatus::Corrupted { .. })
}

Try / catch

try {
  await invoke('parakeet_delete_corrupted_model', { modelName });
} catch (e) {
  if (String(e).includes('Can only delete')) {
    // state problem, not a failure: cancel download or refresh list, never blind-retry
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of Zackriya-Solutions/meetily@a2cb62e827 (2026-08-16). Data as JSON: /api/errors/e9e250389cbf8141. Report an issue: GitHub.

Appendix: source

Thrown at frontend/src-tauri/src/parakeet_engine/parakeet_engine.rs:608

                    fs::remove_dir_all(&model_info.path).await
                        .map_err(|e| anyhow!("Failed to delete directory '{}': {}", model_info.path.display(), e))?;
                    log::info!("Successfully deleted Parakeet model directory: {}", model_info.path.display());
                } else {
                    log::warn!("Directory '{}' does not exist, nothing to delete", model_info.path.display());
                }

                // Update model status to Missing
                {
                    let mut models = self.available_models.write().await;
                    if let Some(model) = models.get_mut(model_name) {
                        model.status = ModelStatus::Missing;
                    }
                }

                Ok(format!("Successfully deleted Parakeet model '{}'", model_name))
            }
            _ => {
                Err(anyhow!(
                    "Can only delete corrupted or available Parakeet models. Model '{}' has status: {:?}",
                    model_name,
                    model_info.status
                ))
            }
        }
    }

    /// Download a Parakeet model from HuggingFace (backward-compatible wrapper).
    pub async fn download_model(
        &self,
        model_name: &str,
        progress_callback: Option<Box<dyn Fn(u8) + Send>>,
    ) -> Result<()> {
        let detailed_callback = progress_callback.map(|callback| {
            Box::new(move |progress: DownloadProgress| callback(progress.percent))
                as Box<dyn Fn(DownloadProgress) + Send>
        });

View on GitHub (pinned to a2cb62e827)