Fix: plugin marketplace installLocation should use portable paths (cross-platform path breakage)
Bug: Cross-platform installLocation in known_marketplaces.json creates mangled directories
Problem
When Claude Code runs inside a Linux container (Docker, WSL2, devcontainer) but ~/.claude is mounted from a Windows host, the plugin marketplace system creates a mangled directory in the project's working directory.
Root cause: known_marketplaces.json is written by the VS Code extension on the Windows host with an absolute Windows path:
{
"claude-plugins-official": {
"installLocation": "C:\\Users\\matte\\.claude\\plugins\\marketplaces\\claude-plugins-official",
...
}
}
When the CLI reads this on Linux:
path.isAbsolute("C:\\Users\\matte\\...")returnsfalse(no/prefix)- The path is treated as relative to CWD
git clonecreates a literal directory namedC:\Users\matte\.claude\plugins\marketplaces\claude-plugins-officialinside the project
Proof — my workspace right now:
$ ls -d /workspace/C*
/workspace/C:\Users\matte\.claude\plugins\marketplaces\claude-plugins-official
Environment
- Windows 11 host with VS Code + Claude Code extension
- Docker container (node:20-slim, Linux) with
~/.claudebind-mounted from host - Claude Code CLI v2.1.79
- Also reproducible on WSL2 (see #26517) and macOS↔devcontainer (#15717)
Related issues (all closed without fix)
- #30114 — my original report, closed as duplicate of ↓
- #26517 — WSL2 variant, closed as duplicate of ↓
- #24503 — Docker variant, closed as duplicate of ↓
- #15717 — original issue (macOS/devcontainer), closed as stale
Suggested fix
The installLocation should be portable across platforms. Two approaches (not mutually exclusive):
Option A: Store relative paths (recommended)
Store installLocation relative to ~/.claude/ instead of as an absolute path:
- "installLocation": "C:\\Users\\matte\\.claude\\plugins\\marketplaces\\claude-plugins-official"
+ "installLocation": "plugins/marketplaces/claude-plugins-official"
At read time, resolve relative to the current ~/.claude/ (or CLAUDE_CONFIG_DIR):
function resolveInstallLocation(loc: string): string {
if (path.isAbsolute(loc)) return loc; // backward compat
return path.join(getConfigDir(), loc);
}
This makes the config inherently portable across Windows/Linux/macOS and across users.
Option B: Detect and sanitize cross-platform paths at read time
When reading installLocation, detect Windows-style paths on Linux (and vice versa) and re-resolve:
function normalizeInstallLocation(loc: string, marketplaceName: string): string {
const isWindows = process.platform === 'win32';
const looksLikeWindowsPath = /^[A-Za-z]:[\\\/]/.test(loc);
if (!isWindows && looksLikeWindowsPath) {
// Windows path on Linux — re-derive from marketplace name
return path.join(getMarketplacesDir(), marketplaceName);
}
const looksLikePosixAbsolute = loc.startsWith('/');
if (isWindows && looksLikePosixAbsolute && !fs.existsSync(loc)) {
return path.join(getMarketplacesDir(), marketplaceName);
}
return loc;
}
Additional guard: validate before git clone
The existing corruption check in s86 (marketplace refresh) should also run before cloning:
const resolved = path.resolve(installLocation);
const marketplacesDir = path.resolve(getMarketplacesDir());
if (!resolved.startsWith(marketplacesDir)) {
// Path would escape the marketplaces directory — re-derive it
installLocation = path.join(marketplacesDir, marketplaceName);
}
This prevents git clone from ever writing outside ~/.claude/plugins/marketplaces/.
Impact
This affects every user running Claude Code CLI in a Linux environment with ~/.claude shared from a Windows host — a very common Docker/devcontainer setup. The bug:
- Pollutes the project directory with a junk folder
- May cause git noise (unless
.gitignored) - Breaks plugin discovery (plugins show as "not found")
- Has been reported 4 times over 3+ months with no resolution
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗