[BUG] Race Condition: Folders Created with Literal Variable Names Before Expansion

Resolved 💬 5 comments Opened Dec 5, 2025 by jurgenmahn Closed Feb 27, 2026

[BUG] Race Condition: Folders Created with Literal Variable Names Before Expansion

Description

Claude Code creates directories with literal unexpanded variable names (e.g., ${CLAUDE_CODE_DATA_DIR}) during initialization, before environment variable expansion occurs. The MCP servers then correctly use the expanded paths, resulting in duplicate folders.

This is distinct from #9427 where variables don't expand at all - in this case, MCP servers work correctly with expanded values, but something in the initialization phase creates folders too early.

Steps to Reproduce

  1. Define a custom environment variable in .claude/settings.local.json:

``json
"env": {
"CLAUDE_CODE_DATA_DIR": "/home/user/claude-code-data"
}
``

  1. Reference it in a plugin's plugin.json MCP server configuration:

``json
"mcpServers": {
"chroma": {
"command": "uvx",
"args": [
"chroma-mcp",
"--data-dir",
"${CLAUDE_CODE_DATA_DIR}/chroma"
]
},
"slack": {
"env": {
"SLACK_MCP_USERS_CACHE": "${CLAUDE_CODE_DATA_DIR}/.slack_users_cache.json"
}
}
}
``

  1. Start Claude Code
  2. Check project directory with ls -la

Expected Behavior

  • Only the expanded path (/home/user/claude-code-data/chroma) should be created
  • No folder named literally ${CLAUDE_CODE_DATA_DIR} should exist in the project directory

Actual Behavior

$ ls -la /home/jurgen/sites/claude-agents/
drwxrwxr-x  3 jurgen jurgen  4096 Dec  5 12:32 ${CLAUDE_CODE_DATA_DIR}  # ← Literal folder created!

$ ls -la /home/jurgen/claude-code-data/
drwxrwxr-x  3 jurgen jurgen   4096 Dec  5 12:32 chroma                   # ← Correct expanded path
-rw-r--r--  1 jurgen jurgen  66190 Dec  5 03:25 .slack_channels_cache.json
-rw-r--r--  1 jurgen jurgen 134061 Dec  5 03:25 .slack_users_cache.json

Evidence:

  • MCP servers successfully write data to expanded path /home/jurgen/claude-code-data/
  • Literal ${CLAUDE_CODE_DATA_DIR}/ folder exists but remains empty
  • Both folders coexist, proving this is a timing issue not an expansion failure

Impact

  • Creates confusing literal ${...} folders in project directories
  • Pollutes workspaces with stale empty directories
  • Wastes disk space with duplicate directory trees
  • Makes debugging MCP server paths confusing (which folder is being used?)

Root Cause (Analysis)

This appears to be a race condition in the initialization sequence:

  1. ✅ Settings are loaded
  2. Something creates directories (pre-flight check? MCP setup?) - uses literal strings
  3. ✅ Environment variables are expanded
  4. ✅ MCP servers start with correct expanded values

The directory creation logic runs before variable expansion, but MCP server execution runs after expansion.

Relationship to Existing Issues

  • #9427 (open) - Variables not expanding in plugin .mcp.json for authentication
  • #3239 (closed, regressed) - Variable expansion not working in .mcp.json
  • #7960 - Unwanted directory creation in CWD

This bug is distinct: MCP servers work correctly, but something creates directories too early.

Environment

  • Platform: Linux 6.14.0-36-generic
  • Claude Code version: [latest as of 2025-12-05]
  • Plugin: Custom plugin with MCP servers (chroma, slack, gitlab)
  • Variable defined in: .claude/settings.local.json
  • Variable used in: .claude-plugin/plugin.json

Suggested Fix

Ensure environment variable expansion happens before:

  1. Any directory creation related to MCP server paths
  2. MCP server argument/config pre-processing
  3. Pre-flight checks that might create directories

Workaround

None known - literal folders must be manually deleted periodically.

View original on GitHub ↗

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