[BUG] plugin uninstall resolves by bare name, can silently uninstall an unrelated enabled plugin sharing the same name in a different marketplace

Status Fixed / completed
Reported on v2.1.205
Maintainer reply ✓ Yes — bcherny
Activity 3 comments · opened Jul 9, 2026 · closed Aug 17, 2026
💡 Likely answer: A maintainer (bcherny, collaborator) responded on this thread — see the highlighted reply below.

Description

claude plugin uninstall <id> resolves plugins by bare name internally in at least one code path, even when the caller passes a fully-qualified plugin@marketplace id. When two different marketplaces each have an installed plugin sharing the same short name, uninstalling the disabled one by its fully-qualified id can silently uninstall the other, unrelated, enabled plugin instead — while leaving the intended target still installed.

Environment

  • claude --version: 2.1.205
  • macOS

Repro

Two plugins named superpowers were installed at user scope, from two different marketplaces:

{
  "id": "superpowers@claude-plugins-official",
  "version": "6.1.1",
  "scope": "user",
  "enabled": false
}
{
  "id": "superpowers@superpowers-marketplace",
  "version": "5.1.0",
  "scope": "user",
  "enabled": true
}

Ran:

claude plugin uninstall superpowers@claude-plugins-official -s user --keep-data -y

Output:

✔ Successfully uninstalled plugin: superpowers (scope: user)

(Note the success message drops the marketplace qualifier entirely — only prints the bare name, which is what tipped me off to the likely root cause.)

Expected

Only superpowers@claude-plugins-official is removed from ~/.claude/plugins/installed_plugins.json / claude plugin list --json. superpowers@superpowers-marketplace (enabled, different marketplace, different install path/version) is untouched.

Actual

claude plugin list --json immediately after the command showed:

  • superpowers@claude-plugins-official — still present, still enabled: false (the intended target was never actually removed)
  • superpowers@superpowers-marketplace — gone entirely from the list (not just disabled — fully uninstalled, dropped from installed_plugins.json)

This was a real, enabled, actively-used plugin (invoked dozens of times/month in this account's usage history) that got silently removed as a side effect of uninstalling an unrelated, disabled, same-named plugin from a different marketplace.

Workaround / recovery

claude plugin enable superpowers@superpowers-marketplace -s user re-triggered a full reinstall (fresh fetch from the marketplace source, since it had been fully uninstalled rather than just disabled) and restored it correctly.

Impact / why this matters

This happened while batch-uninstalling ~83 disabled, zero-usage plugins from claude-plugins-official to shrink /context's skill catalog footprint (a large fraction of installed marketplace plugins were disabled-but-never-uninstalled, each still contributing "always-on" token cost per claude plugin details — a separate but related discoverability gap worth its own docs note: disable does not remove a plugin's contribution to context token cost, only uninstall does). In a batch operation over dozens of plugins, this bug is easy to trigger blind (any bare-name collision across two installed marketplaces) and easy to miss (the CLI reports success either way, and the collateral damage is a different plugin than the one targeted — nothing in the uninstall output or exit code signals anything went wrong).

Suggested fix: uninstall (and likely enable/disable) should resolve strictly by the fully-qualified plugin@marketplace id end-to-end, never falling back to/matching on bare name once a marketplace qualifier is provided. At minimum, the success message should always echo the fully-qualified id that was actually acted on, so this kind of mismatch is visible immediately.

View original on GitHub ↗

3 Comments

dudupmoreira · 3 months ago

Found what looks like a related-but-distinct manifestation of the same underlying plugin-identity-resolution issue, while auditing a large local plugin registry (~/.claude/plugins/installed_plugins.json).

Symptom: claude plugin details <id> fails with Plugin "<id>" not found. Run \claude plugin list\ to see installed plugins... even though claude plugin list --json clearly shows the id installed (and even though the plugin's cache directory exists on disk).

Root cause (confirmed): it happens specifically when the same fully-qualified id (name@marketplace) has two registrations at different scopes (project and user) simultaneously, both disabled. In our case:

"circleback@claude-plugins-official": [
  { "scope": "project", "projectPath": "/Users/<redacted>", "version": "1.0.0", ... },
  { "scope": "user", "version": "1.0.0", ... }
],
"ralph-wiggum@claude-code-plugins": [
  { "scope": "project", "projectPath": "/Users/<redacted>", "version": "1.0.0", ... },
  { "scope": "user", "version": "1.0.0", ... }
]

Both entries are enabled: false. claude plugin details --help has no -s/--scope flag to disambiguate, so the internal lookup apparently can't resolve a single match and returns "not found" instead of picking one (or erroring more informatively).

Across our full registry (34 distinct ids at the time), these were the only two ids with more than one scope registration — every other id had exactly one entry, and details worked fine for all of them (including other disabled plugins).

This is a different trigger than the bug reported above (bare-name collision across different marketplaces during uninstall) — this one is same-marketplace, same-name, duplicate-scope registration, and it reproduces on details (we didn't risk testing uninstall on it given the collateral damage already seen with the bare-name case). Given the identity-resolution logic is shared code, wanted to flag it here rather than open a separate issue, in case it's the same fix. Happy to open a separate issue instead if that's preferred — let me know.

The project scope entries in our case were incidental (projectPath == $HOME, from having run claude directly in the home directory at some point) rather than a real per-project install, if that's a useful reproduction hint.

Worked around it locally by editing installed_plugins.json directly (removing the redundant scope-duplicate entries) rather than going through uninstall/details, since those code paths are the ones affected.

bcherny collaborator · 1 month ago

Thanks for the detailed repro — I followed it exactly on 2.1.233 (Linux): two local git marketplaces each containing a plugin named dupname, both installed at user scope, one disabled, then claude plugin uninstall dupname@<marketplace> in both directions (and the reverse disable/uninstall order).

In every case the correct plugin was uninstalled: the fully-qualified id resolved to the right marketplace's plugin, and the other same-named plugin stayed installed with its enabled/disabled state intact in both installed_plugins.json and claude plugin list.

This was fixed in 2.1.212 — see "Fixed … plugin uninstall targeting the wrong marketplace …" in the changelog (you reported on 2.1.205, which predates the fix).

Closing as already fixed — if you still see this on 2.1.212 or later, please reply with your version and the exact commands and we'll reopen.

🤖 Generated with Claude Code

github-actions[bot] · 8 days ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.