Plugin cache: a new version dir inherits the previous one's untracked files, replicating them forever

Status Open
Reported on v2.1.261
Maintainer reply None cached
Activity 0 comments · opened Sep 5, 2026

Summary

When a plugin updates, the new cache version directory appears to be seeded from the previous version directory before the fetched content is overlaid. Files that are not part of the plugin at all — untracked, gitignored, or written by a session — are carried into every subsequent version and never collected.

One npm install, run once inside a plugin cache directory in August, had been replicated into 13 version directories by early September: 1.2 GB for a plugin whose actual content is ~100 MB.

Evidence

Each version directory's stray node_modules carries the previous version directory's mtime:

dir                dir mtime      node_modules mtime
0ad050c57d55       09-03 21:03    09-03 20:12   <- 9293c4174301's dir mtime
9293c4174301       09-03 20:12    09-02 19:50
18305c8e2988       09-02 20:24    09-02 10:50   <- afa75660303d's dir mtime
afa75660303d       09-02 10:50    09-01 16:24   <- 8da88c0b75c8's dir mtime
8da88c0b75c8       09-01 16:24    09-01 15:52
dcf0e39243ff       09-01 16:21    08-29 15:15   <- 55e352c658c7's dir mtime
55e352c658c7       08-29 15:15    08-28 08:55   <- cdd94257f637's dir mtime
cdd94257f637       08-28 08:55    08-25 18:59   <- b1659cee6616's dir mtime (19:12)
b1659cee6616       08-25 19:12    08-23 16:06   <- 1699ab277632's dir mtime

Nine of thirteen chain exactly. The copies are real, not hardlinks — distinct inodes, st_nlink = 1 on both sides of a sampled pair.

The plugin's own remote is clean: node_modules is gitignored, untracked, and absent from the default branch (checked via the contents API). The plugin declares no hooks and no install scripts. So nothing about the plugin explains the directory's presence — only the copy-forward does.

Why it is worth fixing beyond the disk

Anything ever written into a plugin cache directory becomes permanent and self-replicating. A file dropped there once — a scratch artifact, a log, a credential a session wrote while debugging — propagates into every future version of that plugin and survives updates that were expected to replace the tree. The cache stops being a cache and becomes an append-only accumulation, and nothing surfaces it.

Expected

A new version directory contains the plugin's fetched content and nothing else. Either populate it from a clean fetch, or carry forward only paths the plugin declares.

Environment

Claude Code 2.1.261, macOS 15 (arm64). Plugin installed from a marketplace entry with source: { source: "url", url: "…git" }.

View original on GitHub ↗