[BUG] Plugin cache creates infinite recursive directories when marketplace.json and plugin.json coexist in same repo

Resolved 💬 5 comments Opened Mar 18, 2026 by berrzebb Closed Apr 15, 2026

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

  1. 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/...
``

  1. marketplace.json references its own repo as the plugin source:

``json
{
"plugins": [{
"name": "my-plugin",
"source": { "source": "github", "repo": "owner/my-plugin" }
}]
}
``

  1. Run claude plugin add owner/my-plugin
  1. 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.json from 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.

View original on GitHub ↗

This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗