.claude.json corrupts on Windows with multiple sessions — silent config loss
Bug Summary
~/.claude.json corrupts when multiple Claude Code sessions run concurrently on the same machine. The recovery process silently drops critical config sections (e.g., mcpServers), requiring manual backup restoration.
Root Cause
Claude Code writes to ~/.claude.json on every session (updating toolUsage, clientDataCache.timestamp, changelogLastFetched, etc.). With multiple sessions open, concurrent writes race and one truncates the file mid-write, producing invalid JSON (Unexpected EOF).
Current Recovery Behavior (Broken)
When corruption is detected on startup:
- Corrupted file is backed up to
~/.claude/backups/.claude.json.corrupted.<timestamp> - A previous backup is offered for restoration
- If no restoration happens, a minimal new file is created with only basic keys
Problem: The minimal file drops mcpServers and other user-configured sections entirely. No merge is attempted. The user loses their MCP server configuration (potentially 10+ servers) silently.
Observed Symptoms
- Error on startup:
Claude configuration file at ~/.claude.json is corrupted: JSON Parse error: Unexpected EOF userIDchanges on every session write (4+ different IDs in 7 minutes)mcpServerssection (11 servers) completely gone after recovery- Multiple
.corrupted.*and.backup.*files accumulate in~/.claude/backups/
Proposed Fix (Two Parts)
Part 1: Prevent Corruption — Atomic Writes
Replace direct fs.writeFileSync('~/.claude.json', data) with atomic write pattern:
const tmpPath = configPath + '.tmp.' + process.pid;
fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2));
fs.renameSync(tmpPath, configPath); // atomic on same filesystem
This ensures the file is either fully written or not modified at all. rename() is atomic on POSIX and NTFS (Windows).
Files to change: Search codebase for all writeFileSync or writeFile calls targeting .claude.json or the config path.
Part 2: Smarter Recovery — Merge Instead of Replace
When corruption is detected and a backup exists, the recovery should:
- Parse the backup file
- Parse/create the new minimal config
- Merge user-configured sections from the backup — specifically:
mcpServers(critical — user's MCP server definitions)projects(project-specific settings)- Any other user-configured keys
- Use the current session's runtime values for volatile keys:
userID,toolUsage,clientDataCache,changelogLastFetched, etc.
- Write the merged result (using atomic write from Part 1)
// Pseudocode for recovery merge
const backup = JSON.parse(fs.readFileSync(backupPath));
const fresh = createDefaultConfig();
// Preserve user config from backup
const USER_CONFIG_KEYS = ['mcpServers', 'projects'];
for (const key of USER_CONFIG_KEYS) {
if (backup[key] && Object.keys(backup[key]).length > 0) {
fresh[key] = backup[key];
}
}
atomicWrite(configPath, fresh);
Environment
- OS: Windows 11 Home 10.0.26200
- Claude Code: 2.1.59
- Shell: Git Bash
- Trigger: Multiple concurrent sessions (VS Code terminals + standalone)
Reproduction
- Configure 5+ MCP servers in
~/.claude.jsonundermcpServers - Open 3+ Claude Code sessions simultaneously
- Use them actively for a few minutes (triggers config writes)
- Close and reopen a session — observe corruption error
- Check
~/.claude.json—mcpServersis gone
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗