Plugin loader uses wrong installPath — takes [0] from installed_plugins array instead of filtering by current project
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
pluginLoader.ts line 2051 reads:
const installEntry = installedPluginsData.plugins[pluginId]?.[0]
This takes the first entry in the installed_plugins.json array for a given plugin ID without filtering by the current project context. The array is ordered by insertion time (whichever project installed the plugin first is [0]), so the loader reads the installPath from an unrelated project's entry — loading the wrong plugin version, wrong MCP servers, and wrong commands.
The correct filter function already exists in the same codebase — isInstallationRelevantToCurrentProject() in installedPluginsManager.ts (lines 800–808) — but the loader doesn't use it.
Symptoms
When the same plugin is installed across multiple projects at different versions:
- Wrong MCP servers loaded — e.g., a deprecated
ht-mcpserver from terminal plugin v2.0.0 loads in a project that has v4.0.2 (which only usestmux-mcp) - Wrong commands loaded — old commands like
/deep-researchappear instead of the current/dev:research - New commands missing — commands added in newer versions don't appear because the old version's
commands/directory is used - The project's own
settings.jsonshows the correct version — claudeup's TUI,/plugins, andinstalledPluginVersionsall report v4.0.2, but the actual loaded content comes from v2.0.0
Root Cause
installed_plugins.json (v2 schema) stores an array of entries per plugin ID, one per project scope:
{
"version": 2,
"plugins": {
"terminal@magus": [
{ "scope": "project", "projectPath": "/Users/jack/mag/website", "installPath": "~/.claude/plugins/cache/magus/terminal/2.0.0", "version": "2.0.0" },
{ "scope": "project", "projectPath": "/Users/jack/mag/meroku", "installPath": "~/.claude/plugins/cache/magus/terminal/4.0.2", "version": "4.0.2" },
... // 19 more entries from other projects
]
}
}
The loader at pluginLoader.ts:2051 does ?.[0] which returns the website entry (v2.0.0) even when Claude Code is running in the meroku directory (v4.0.2).
Meanwhile, isInstallationRelevantToCurrentProject() already exists and correctly filters:
export function isInstallationRelevantToCurrentProject(
inst: PluginInstallationEntry,
): boolean {
return (
inst.scope === 'user' ||
inst.scope === 'managed' ||
inst.projectPath === getOriginalCwd()
)
}
Suggested Fix
Replace line 2051:
// Before (bug):
const installEntry = installedPluginsData.plugins[pluginId]?.[0]
// After (fix):
const entries = installedPluginsData.plugins[pluginId] ?? []
const installEntry = entries.find(isInstallationRelevantToCurrentProject) ?? entries[0]
The ?? entries[0] fallback preserves current behavior if no entry matches (shouldn't happen in practice).
Steps to Reproduce
- Install a marketplace plugin (e.g.,
terminal@magus) in Project A at version 2.0.0 - Later, install the same plugin in Project B at version 4.0.2
- Start Claude Code in Project B
- Observe: the plugin loads from Project A's cached v2.0.0 directory, not Project B's v4.0.2
Impact
- Security: old plugin versions may have deprecated/insecure MCP servers that connect and accept tool calls
- Correctness: wrong commands, wrong skills, wrong MCP tools loaded — breaks the entire plugin experience
- Confusing UX: every diagnostic (
/plugins, settings.json, claudeup) shows the correct version, but the actual runtime behavior uses a different version - Scale: the bug worsens as users install plugins across more projects — the first-installed project permanently "wins" the installPath
Related Issues
- #29074 — Plugin cache not cleared on uninstall/reinstall (related: stale cache versions)
- #43763 — installed_plugins.json not updated when version changes (related: registry staleness)
Claude Code Version
2.1.98
Platform
Anthropic API (Max)
Operating System
macOS (Darwin 25.4.0, arm64)
Terminal/Shell
Zsh (inside tmux)
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗