Windows: ~/.claude.json corruption from concurrent sessions (race condition in config writes)
Preflight Checklist
- [x] I have searched the existing issues and this has not been reported before
- [x] This is a single bug report, not multiple issues combined
- [x] I am using the latest version of Claude Code
What's Wrong?
On Windows 11, running multiple concurrent Claude Code CLI sessions causes repeated corruption of ~/.claude.json. The file gets truncated mid-write, producing invalid JSON (Unexpected EOF). This causes:
JSON Parse error: Unexpected EOFon every session start- Loss of
oauthAccountdata, forcing re-login every session - Other active sessions breaking with display errors
- Hundreds of
.corruptedbackup files accumulating in~/.claude/backups/(358 files over ~1 week)
What Should Happen?
Multiple concurrent Claude Code sessions should be able to safely read/write ~/.claude.json without corrupting each other's writes. Auth data (oauthAccount) should persist across sessions. The config file should never end up as truncated/invalid JSON.
Steps to Reproduce
- Open 3-4 terminal windows on Windows 11
- Run
claude --dangerously-skip-permissionsin each - Use all sessions concurrently (the config gets written frequently due to
toolUsage,clientDataCache,cachedGrowthBookFeaturesupdates) - After a few minutes, observe:
JSON Parse error: Unexpected EOFerrors appearing- Sessions losing auth and asking to re-login
.corruptedfiles accumulating in~/.claude/backups/
Is this a regression?
Yes, this worked in a previous version
Claude Code Version
2.1.59
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Windows Terminal
Error Messages/Logs
Claude configuration file at C:\Users\levla\.claude.json is corrupted: JSON Parse error: Unexpected EOF
The corrupted file has been backed up to: C:\Users\levla\.claude\backups\.claude.json.corrupted.1772132075540
A backup file exists at: C:\Users\levla\.claude\backups\.claude.json.backup.1772132048488
You can manually restore it by running: cp "C:\Users\levla\.claude\backups\.claude.json.backup.1772132048488" "C:\Users\levla\.claude.json"
Claude Model
Not sure/Multiple models
Last Working Version
Not sure exactly, but this started occurring in the last few weeks. Possibly around 2.1.x.
Additional Information
Root Cause Analysis
Decompiled the bundled JS from the binary and traced the issue to the config write path:
1. Atomic write fallback (writeFileAtomic)
The atomic write correctly uses temp file + renameSync. On Windows, renameSync fails with EPERM when another process has the target file open. The code falls back to a direct non-atomic writeFileSync:
// Pseudocode from decompiled source
function writeFileAtomic(path, data) {
let tempFile = `${path}.tmp.${process.pid}.${Date.now()}`;
try {
fs.writeFileSync(tempFile, data, { flush: true });
fs.renameSync(tempFile, path); // FAILS on Windows with EPERM
} catch {
// Fallback: non-atomic direct write — THIS IS THE BUG
fs.writeFileSync(path, data, { flush: true });
}
}
2. Lock contention (saveConfigWithLock)
Uses proper-lockfile with lockSync(). When lock acquisition fails, saveGlobalConfig catches the error and falls back to a completely unlocked, non-atomic write:
function saveGlobalConfig(callback) {
try {
saveWithLock(configPath, defaults, callback);
} catch {
// FALLBACK: unlocked write when lock fails
saveWithoutLock(configPath, mergedConfig, defaults);
}
}
3. The cascade
- Session A reads config → Session B reads config
- Session A acquires lock, writes (rename fails on Windows) → falls back to direct write
- Session B acquires lock (or fails), starts writing simultaneously
- One write truncates the other → corrupted JSON
- Session C starts, reads corrupted file →
Unexpected EOF - Corruption handler backs up corrupted file, writes minimal config (losing
oauthAccount) - All sessions now need re-login → more writes → more corruption
Evidence
- 358 corrupted backup files in
~/.claude/backups/over ~1 week - Corrupted files are truncated JSON (50-90KB files reduced to 50-157 byte fragments)
- Multiple corrupted files with timestamps within the same second (concurrent writes)
oauthAccountconsistently lost, while transient fields liketoolUsagesurvive (written most frequently)
Suggested Fixes
- Don't fall back to non-atomic writes on Windows. Retry the rename with backoff, or use
MoveFileExwithMOVEFILE_REPLACE_EXISTING. - Use Windows-native file locking (
LockFileEx/fs.openwith exclusive flags) instead ofproper-lockfile's directory-based locking which is unreliable on NTFS under high contention. - Abort stale writes:
tengu_config_stale_writetelemetry already detects when the file changed since read — make it abort the write instead of proceeding. - Separate volatile and stable config: Move frequently-written fields (
toolUsage,clientDataCache,cachedGrowthBookFeatures) to a separate file to reduce write contention on the auth config.
Workaround
Created a PowerShell file watcher that monitors ~/.claude.json, detects corruption via JSON parse validation, and auto-restores from an in-memory snapshot within ~200ms. Also merges back oauthAccount when it gets stripped by a concurrent write.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗