Hmbown/CodeWhale · error
plugin `{selector}` is enabled; disable it first with /plugi
Error message
plugin `{selector}` is enabled; disable it first with /plugin disable {selector} What it means
The plugin uninstall mutation refuses to remove a plugin bundle that is currently enabled. Before touching the filesystem (install::uninstall in the user plugins dir) the code checks plugin.enabled and aborts so an in-use plugin cannot be deleted out from under a running session. This is a deliberate two-step lifecycle: disable first, then uninstall.
Source
Thrown at crates/tui/src/plugins/mutation.rs:214
})
}
fn uninstall_plugin(
selector: &str,
registry: &mut PluginRegistry,
) -> Result<PluginMutationReceipt> {
let plugin = registry
.get(selector)
.with_context(|| format!("Plugin bundle `{selector}` was not found"))?
.clone();
if plugin.scope != PluginScope::User {
bail!(
"refusing to uninstall the {} bundle `{selector}`; remove it from its own root",
plugin.scope.as_str()
);
}
if plugin.enabled {
bail!("plugin `{selector}` is enabled; disable it first with /plugin disable {selector}");
}
let plugins_dir = user_plugins_dir(registry)?;
install::uninstall(plugin.name(), &plugins_dir)?;
registry
.prune_state_entry(selector)
.map_err(anyhow::Error::msg)?;
Ok(PluginMutationReceipt {
name: plugin.name().to_string(),
path: None,
content_hash: None,
installed_content_hash: None,
outcome: PluginMutationOutcome::Uninstalled,
})
}
fn blocked(host: String, needs_approval: bool) -> PluginMutationReceipt {
PluginMutationReceipt {
name: String::new(),View on GitHub (pinned to 0c42157ee5)
Solutions
- Run /plugin disable {selector} first, then retry /plugin uninstall {selector}.
- Verify the plugin's current state with /plugin list (or registry.get(selector)) to confirm it shows disabled before uninstalling.
- If the registry state looks wrong (plugin shows enabled but is not really loaded), prune or repair the plugin state entry, then retry disable + uninstall.
- Script authors: make uninstall a two-command sequence (disable, then uninstall) and tolerate 'already disabled' on the first step.
Example fix
# before codewhale /plugin uninstall my-plugin # fails: plugin is enabled # after codewhale /plugin disable my-plugin codewhale /plugin uninstall my-plugin
Defensive patterns
Strategy: validation
Validate before calling
// Rust: check registry state before uninstalling
let plugin = registry.get(selector)
.with_context(|| format!("Plugin bundle `{selector}` was not found"))?;
if plugin.scope != PluginScope::User {
anyhow::bail!("cannot uninstall non-user bundle; remove it from its own root");
}
if plugin.enabled {
disable_plugin(registry, selector)?; // /plugin disable equivalent
}
uninstall_plugin(registry, selector)?; Try / catch
// Treat as a recoverable state error: match on the message prefix and retry once after disabling
match uninstall_plugin(®istry, selector) {
Err(err) if err.to_string().contains("is enabled; disable it first") => {
disable_plugin(®istry, selector)?;
uninstall_plugin(®istry, selector)?;
}
other => other?,
} Prevention
- Model plugin removal as an explicit disable-then-uninstall sequence in scripts and UI flows.
- Surface plugin.enabled state in any management UI next to the uninstall action.
- Treat 'already disabled' as success in automated disable steps so reruns are idempotent.
When it happens
Trigger: Calling the plugin uninstall mutation (the /plugin uninstall path in crates/tui/src/plugins/mutation.rs) with a selector whose registry entry has enabled == true. It also only proceeds for PluginScope::User bundles, so builtin/workspace bundles fail earlier with a different message.
Common situations: A user tries to remove a plugin they installed earlier without first turning it off; automation scripts that install/upgrade plugins call uninstall directly and forget the disable step; stale registry state still marks a plugin as enabled after a manual edit of plugin state files.
Related errors
- terminal lane transition requires a terminal status
- lane `{}` was stopped before tmux launch
- lane `{}` was stopped before inline start completed
- unsupported locale '{other}'
- invalid locale '{value}'
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/d1ee8daf019ad9f8.
Report an issue: GitHub.