[BUG] Plugin cache creates infinite recursive directories when marketplace.json and plugin.json coexist in same repo
Summary
When a plugin repository contains both .claude-plugin/marketplace.json and .claude-plugin/plugin.json at the root level (self-hosted marketplace), claude plugin add creates an infinitely recursive directory structure in the plugin cache.
Reproduction Steps
- Create a plugin repo with both files at root:
````
my-plugin/
.claude-plugin/
marketplace.json ← declares this repo as a marketplace
plugin.json ← declares this repo as a plugin
hooks/hooks.json
skills/...
marketplace.jsonreferences its own repo as the plugin source:
``json``
{
"plugins": [{
"name": "my-plugin",
"source": { "source": "github", "repo": "owner/my-plugin" }
}]
}
- Run
claude plugin add owner/my-plugin
- Check the cache directory:
````
~/.claude/plugins/cache/my-plugin/my-plugin/1.0.0/my-plugin/1.0.0/my-plugin/1.0.0/...
Expected Behavior
The plugin should be cached once at cache/<marketplace>/<plugin>/<version>/ without recursion. The cache system should either:
- Detect self-referencing marketplace sources and stop after one copy
- Strip
.claude-plugin/marketplace.jsonfrom cached plugin copies - Refuse to cache a plugin whose source points back to the marketplace repo itself
Actual Behavior
Each cached copy contains .claude-plugin/marketplace.json, which the system re-interprets as a marketplace on the next update pass, creating another level of nesting. The recursion continues until the OS path length limit is hit.
cache/my-plugin/
my-plugin/
2.2.0/
my-plugin/ ← recursive: this shouldn't exist
2.2.0/
my-plugin/ ← keeps going
2.2.0/
...
Root Cause Analysis
The plugin cache system copies the entire source repo (including .claude-plugin/) into the cache directory. When the source repo IS the marketplace repo, the cached copy also looks like a valid marketplace, triggering re-caching on the next scan.
Official plugins avoid this because claude-plugins-official keeps the marketplace.json at the repo root and plugin code in plugins/<name>/ subdirectories — the plugin directory never contains a marketplace.json.
Environment
- Claude Code version: latest (2026-03-18)
- Platform: Windows 11 Pro (win32)
- Plugin: berrzebb/consensus-loop (self-hosted marketplace)
Workaround
Move marketplace.json to a separate repository, following the pattern used by claude-plugins-official.
This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗