claude-code - 💡(How to fix) Fix [plugin] installed_plugins.json accumulates stale installPath entries; PATH wired to ghost dirs [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#54905Fetched 2026-05-01 05:51:22
View on GitHub
Comments
0
Participants
1
Timeline
6
Reactions
0
Author
Participants
Timeline (top)
labeled ×3cross-referenced ×2referenced ×1

Error Message

  • On session start, before wiring PATH, verify each registered installPath exists. If not, either skip it or warn the user that the plugin is in an inconsistent state.

Root Cause

This blocks adopters from using the plugin. The plugin's documented install / usage path produces a state where the bin is unreachable; the user has no in-band recovery. The current workaround documented downstream is "edit installed_plugins.json by hand, remove the bad entries, then reinstall." That is brittle and not user-friendly.

The bug appears to scale with usage — entries accumulate on every install / reinstall / upgrade cycle. A user who has been actively iterating on a plugin (across version bumps, marketplace updates, plugin enable/disable cycles) is more likely to land in the broken state than a fresh adopter.

Fix Action

Fix / Workaround

This blocks adopters from using the plugin. The plugin's documented install / usage path produces a state where the bin is unreachable; the user has no in-band recovery. The current workaround documented downstream is "edit installed_plugins.json by hand, remove the bad entries, then reinstall." That is brittle and not user-friendly.

Downstream mitigation

Code Example

$ ls ~/.claude/plugins/cache/deskwork/
deskwork-studio                 # only directory present

$ node -e 'const d = JSON.parse(require("fs").readFileSync(process.env.HOME + "/.claude/plugins/installed_plugins.json", "utf8")); for (const [k, vs] of Object.entries(d.plugins)) { if (!/deskwork/.test(k)) continue; for (const v of vs) console.log(k, "version=" + v.version, "exists=" + require("fs").existsSync(v.installPath)); }'

deskwork@deskwork version=0.9.7 exists=false
deskwork@deskwork version=0.0.1 exists=false
deskwork@deskwork version=0.7.2 exists=false
deskwork@deskwork version=0.9.5 exists=false
deskwork@deskwork version=0.9.7 exists=false
deskwork@deskwork version=0.9.7 exists=false
deskwork-studio@deskwork version=0.7.2 exists=true
deskwork-studio@deskwork version=0.9.5 exists=false
deskwork-studio@deskwork version=0.9.7 exists=false
deskwork-studio@deskwork version=0.9.7 exists=false
dw-lifecycle@deskwork version=0.9.7 exists=false

$ command -v deskwork dw-lifecycle deskwork-studio
/Users/orion/.claude/plugins/cache/deskwork/deskwork-studio/0.7.2/bin/deskwork-studio    # only one resolves

$ echo $PATH | tr : '\n' | grep deskwork
/Users/orion/.claude/plugins/cache/deskwork/deskwork/0.9.4/bin       # ghost path — directory doesn't exist
/Users/orion/.claude/plugins/cache/deskwork/deskwork-studio/0.7.2/bin

---

~/.claude/plugins/marketplaces/deskwork/plugins/deskwork/bin/deskwork repair-install
RAW_BUFFERClick to expand / collapse

Symptom

~/.claude/plugins/installed_plugins.json accumulates entries pointing at cache directories that no longer exist on disk. Claude Code wires PATH from these stale entries on session start, so command -v <plugin-bin> returns empty even when:

  • The marketplace clone at ~/.claude/plugins/marketplaces/<marketplace>/plugins/<plugin>/bin/<bin> is intact and runs cleanly.
  • /plugin install <plugin>@<marketplace> reports success.
  • /plugin marketplace update <marketplace> reports success.
  • /reload-plugins reports the expected number of plugins loaded.

The user-facing failure is "I just installed the plugin and command -v <bin> returns nothing." There is no diagnostic surface that reveals the cache vs registry mismatch.

Concrete reproduction (deskwork plugin marketplace)

State on a development machine after several install / upgrade / reload cycles:

$ ls ~/.claude/plugins/cache/deskwork/
deskwork-studio                 # only directory present

$ node -e 'const d = JSON.parse(require("fs").readFileSync(process.env.HOME + "/.claude/plugins/installed_plugins.json", "utf8")); for (const [k, vs] of Object.entries(d.plugins)) { if (!/deskwork/.test(k)) continue; for (const v of vs) console.log(k, "version=" + v.version, "exists=" + require("fs").existsSync(v.installPath)); }'

deskwork@deskwork version=0.9.7 exists=false
deskwork@deskwork version=0.0.1 exists=false
deskwork@deskwork version=0.7.2 exists=false
deskwork@deskwork version=0.9.5 exists=false
deskwork@deskwork version=0.9.7 exists=false
deskwork@deskwork version=0.9.7 exists=false
deskwork-studio@deskwork version=0.7.2 exists=true
deskwork-studio@deskwork version=0.9.5 exists=false
deskwork-studio@deskwork version=0.9.7 exists=false
deskwork-studio@deskwork version=0.9.7 exists=false
dw-lifecycle@deskwork version=0.9.7 exists=false

$ command -v deskwork dw-lifecycle deskwork-studio
/Users/orion/.claude/plugins/cache/deskwork/deskwork-studio/0.7.2/bin/deskwork-studio    # only one resolves

$ echo $PATH | tr : '\n' | grep deskwork
/Users/orion/.claude/plugins/cache/deskwork/deskwork/0.9.4/bin       # ghost path — directory doesn't exist
/Users/orion/.claude/plugins/cache/deskwork/deskwork-studio/0.7.2/bin

11 registered entries, 1 valid path on disk. PATH includes a ghost entry (deskwork/0.9.4/bin) for a version that hasn't existed on disk for several releases.

Why this matters

This blocks adopters from using the plugin. The plugin's documented install / usage path produces a state where the bin is unreachable; the user has no in-band recovery. The current workaround documented downstream is "edit installed_plugins.json by hand, remove the bad entries, then reinstall." That is brittle and not user-friendly.

The bug appears to scale with usage — entries accumulate on every install / reinstall / upgrade cycle. A user who has been actively iterating on a plugin (across version bumps, marketplace updates, plugin enable/disable cycles) is more likely to land in the broken state than a fresh adopter.

Expected behavior

  • On /plugin install, prune any prior entries for the same <plugin>@<marketplace> key whose installPath doesn't exist on disk before adding the new entry.
  • On /reload-plugins, reconcile the registry against the cache directories. Stale entries (registered but missing on disk) should either be re-materialized from the marketplace clone or pruned.
  • On session start, before wiring PATH, verify each registered installPath exists. If not, either skip it or warn the user that the plugin is in an inconsistent state.

Suggested minimal fix

The PATH-wire on session start is the highest-leverage point. A check that filters installPath entries against fs.existsSync before appending them to PATH would prevent the ghost-path symptom alone. The accumulation problem (entries never being pruned) can be addressed separately.

Downstream mitigation

The deskwork project shipped a deskwork repair-install subcommand (v0.9.8) that prunes stale entries for *@deskwork keys. It runs portably via the marketplace-clone bin path so adopters with broken PATH can self-heal:

~/.claude/plugins/marketplaces/deskwork/plugins/deskwork/bin/deskwork repair-install

Each plugin marketplace would have to ship its own equivalent for full coverage. A first-party fix in Claude Code is the cleaner path.

Environment

  • Claude Code: 2.1.121 (AI_AGENT=claude-code/2.1.121/agent)
  • macOS: Darwin 24.6.0
  • Plugin marketplace: audiocontrol-org/deskwork (3 plugins)
  • All three plugins were installed via the canonical /plugin marketplace add + /plugin install flow at various points.

Related downstream issue

audiocontrol-org/deskwork#89 — full timeline of the dogfood discoveries that motivated this report, including the v0.9.5+ fresh-install cases that contradict the original "no release blocker" framing.

extent analysis

TL;DR

Filtering installPath entries against fs.existsSync before appending them to PATH on session start can prevent the ghost-path symptom.

Guidance

  • On session start, verify each registered installPath exists using fs.existsSync before wiring PATH to prevent ghost paths.
  • Consider pruning stale entries for the same <plugin>@<marketplace> key whose installPath doesn't exist on disk before adding a new entry on /plugin install.
  • Reconcile the registry against the cache directories on /reload-plugins to remove stale entries.
  • Implement a check to warn the user if a plugin is in an inconsistent state due to a missing installPath.

Example

const fs = require('fs');
const path = require('path');

// On session start, filter installPath entries
const installedPlugins = JSON.parse(fs.readFileSync(installedPluginsJson, 'utf8'));
const validPaths = installedPlugins.plugins.filter(plugin => fs.existsSync(plugin.installPath));
// Append valid paths to PATH

// On /plugin install, prune stale entries
const newPlugin = { ... };
const existingPlugin = installedPlugins.plugins.find(plugin => plugin.key === newPlugin.key);
if (existingPlugin && !fs.existsSync(existingPlugin.installPath)) {
  // Remove existingPlugin from installedPlugins
}

Notes

The provided example is a simplified illustration and may require adjustments to fit the actual implementation. The suggested fix focuses on preventing the ghost-path symptom, while the accumulation problem can be addressed separately.

Recommendation

Apply the suggested fix to filter installPath entries against fs.existsSync before appending them to PATH on session start, as it directly addresses the user-facing issue and provides a foundation for further improvements.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

  • On /plugin install, prune any prior entries for the same <plugin>@<marketplace> key whose installPath doesn't exist on disk before adding the new entry.
  • On /reload-plugins, reconcile the registry against the cache directories. Stale entries (registered but missing on disk) should either be re-materialized from the marketplace clone or pruned.
  • On session start, before wiring PATH, verify each registered installPath exists. If not, either skip it or warn the user that the plugin is in an inconsistent state.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix [plugin] installed_plugins.json accumulates stale installPath entries; PATH wired to ghost dirs [1 participants]