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

  1. Run /plugin disable {selector} first, then retry /plugin uninstall {selector}.
  2. Verify the plugin's current state with /plugin list (or registry.get(selector)) to confirm it shows disabled before uninstalling.
  3. 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.
  4. 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(&registry, selector) {
    Err(err) if err.to_string().contains("is enabled; disable it first") => {
        disable_plugin(&registry, selector)?;
        uninstall_plugin(&registry, selector)?;
    }
    other => other?,
}

Prevention

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


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/d1ee8daf019ad9f8. Report an issue: GitHub.