Hmbown/CodeWhale · error

cannot install a bundle from inside the user plugins…

Error message

cannot install a bundle from inside the user plugins directory {}; it is already in place

What it means

`stage_local_copy` refuses to stage a local bundle whose canonical path is inside the user plugins directory — those files are already installed in place, and copying them onto themselves via staging is meaningless/dangerous. The error reports the canonical plugins dir.

Solutions

  1. Install from the original source location outside the plugins directory
  2. If the bundle is already installed in place, no install is needed — enable it instead (`/plugin enable <name>`)
  3. Move the bundle out of the plugins dir first if you truly need to (re)install it

Example fix

// before
/plugin install ~/.codewhale/plugins/myplugin
// after: install from the project source
/plugin install ~/projects/myplugin
Defensive patterns

Strategy: validation

Validate before calling

let canon_source = fs::canonicalize(source_path)?;
let canon_plugins = fs::canonicalize(user_plugins_dir)?;
if canon_source.starts_with(&canon_plugins) {
    eprintln!("source is already inside the plugins dir; nothing to install");
    return;
}

Try / catch

match install(path) {
    Err(e) if e.to_string().contains("already in place") => {
        eprintln!("bundle already lives in the plugins dir; enable it instead");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `/plugin install <path>` (through `install_inner` → `stage_local_copy`) where `<path>` is inside (or equals) the user plugins directory, e.g. installing a plugin from the very directory it would be installed into.

Common situations: Running install with the plugins dir itself as the source path; installing a subdirectory of the plugins dir; pointing the install source at `~/.codewhale/plugins/...` by mistake.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/ecbbfe8ce9bb6213. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/plugins/install/stage.rs:108

    max_size: u64,
) -> Result<StagedPlugin> {
    // Validate the source first; this also rejects symlinked roots/manifests.
    let manifest_path =
        crate::plugins::agent_plugin::resolve_manifest_path(source).ok_or_else(|| {
            anyhow::anyhow!(
                "source is not a valid plugin bundle: no plugin.json, .claude-plugin/plugin.json, kimi.plugin.json, or plugin.toml"
            )
        })?;
    PluginManifest::validate_from_path(&manifest_path)
        .map_err(|error| anyhow::anyhow!("source is not a valid plugin bundle: {error}"))?;
    let canonical_source = source
        .canonicalize()
        .with_context(|| format!("failed to resolve {}", source.display()))?;
    if let Ok(canonical_plugins) = user_plugins_dir.canonicalize()
        && (canonical_source == canonical_plugins
            || canonical_source.starts_with(&canonical_plugins))
    {
        bail!(
            "cannot install a bundle from inside the user plugins directory {}; \
             it is already in place",
            canonical_plugins.display()
        );
    }

    let staged_path = fresh_staging_dir(user_plugins_dir)?;
    let result = (|| -> Result<StagedPlugin> {
        let mut budget = CopyBudget::default();
        copy_bundle_regular_files(&canonical_source, &staged_path, max_size, &mut budget)?;
        let (name, content_hash) = validate_staged(&staged_path)?;
        Ok(StagedPlugin {
            name,
            staged_path: staged_path.clone(),
            content_hash,
        })
    })();
    if result.is_err() {

View on GitHub (pinned to 73e0f67d83)