Windows: .claude.json corruption from concurrent writes causes repeated OAuth login
Resolved 💬 3 comments Opened Feb 26, 2026 by Shun-toda Closed Mar 3, 2026
Bug Description
On Windows, .claude.json gets repeatedly corrupted by concurrent file writes from multiple Claude Code processes (main session + subagents spawned via Task tool). When corruption is detected, Claude Code resets the config to defaults, losing oauthAccount and other critical fields. This forces a browser OAuth login on every restart.
Environment
- OS: Windows 10 (MSYS_NT-10.0-26100), Git Bash
- Claude Code version: 2.1.59
- Install method: native
- Shell: bash (Git Bash)
Steps to Reproduce
- Start Claude Code on Windows
- Run any workflow that spawns multiple subagents via Task tool (e.g., parallel research tasks)
- Exit Claude Code
- Restart Claude Code → browser OAuth login is required every time
Root Cause (from debug logs)
The corruption follows this sequence:
1. Lock contention between concurrent processes
[ERROR] Failed to save config with lock: Error: Lock file is already being held
2. Atomic write (temp + rename) fails on Windows
[ERROR] Failed to write file atomically: Error: EPERM: operation not permitted, rename '...\.claude.json.tmp.356112...' -> '...\.claude.json'
3. Fallback non-atomic write also fails
Falling back to non-atomic write for C:\Users\...\.claude.json
4. File ends up truncated/corrupted
[ERROR] Config file corrupted, resetting to defaults: JSON Parse error: Unexpected EOF
[ERROR] Corrupted config backed up to: C:\Users\...\.claude\backups\.claude.json.corrupted.1772141474872
5. Reset to defaults loses oauthAccount → login required on next startup
Evidence
- 100+ corrupted backup files found in
~/.claude/backups/(sizes ranging from 43 bytes to 11,886 bytes — clearly truncated mid-write) - File write frequency:
.claude.jsonis written multiple times per second during normal operation (toolUsage, tipsHistory, clientDataCache, etc.) - Corruption pattern: Files are truncated at random points, consistent with concurrent write race conditions
- The
userIDfield changes on every restart (new random hash generated after reset)
Impact
- Every restart requires browser OAuth login (completely blocks headless/automated workflows)
- All session-specific config (
projects,tipsHistory,skillUsage, migration flags) is lost on each corruption - The corruption cycle is self-reinforcing: reset → minimal config → more frequent writes to rebuild → more corruption
Suggested Fixes
- Reduce write frequency: Batch config updates instead of writing on every field change
- Windows-safe file locking: Use
proper-lockfileor OS-level advisory locks instead of the current mechanism that fails with EPERM - Smarter recovery: When corruption is detected, restore from the most recent valid backup in
~/.claude/backups/instead of resetting to empty defaults (the backups directory already contains valid configs) - Separate auth state: Store
oauthAccountand critical auth fields in a separate file that is written infrequently, rather than in the heavily-written.claude.json
Workaround Attempted
- Restoring
oauthAccountfrom backup before launch (via wrapper script) — did not resolve the login issue, suggesting Claude Code checks additional state beyond just the presence ofoauthAccount - Setting
.claude.jsonas read-only (attrib +R) — blocks corruption but causes EPERM errors that interfere with normal operation
Debug Log Excerpts
Full startup sequence showing the problem (from ~/.claude/debug/):
2026-02-26T21:31:14.816Z [DEBUG] Temp file written successfully, size: 532 bytes
2026-02-26T21:31:14.821Z [DEBUG] File .claude.json written atomically
2026-02-26T21:31:14.843Z [ERROR] Failed to save config with lock: Error: Lock file is already being held
2026-02-26T21:31:14.859Z [ERROR] Config file corrupted, resetting to defaults: JSON Parse error: Unexpected EOF
2026-02-26T21:31:14.874Z [ERROR] Corrupted config backed up to: ...\.claude\backups\.claude.json.corrupted.1772141474872
Note: Only 38ms between a successful write and corruption detection — another process overwrote the file in between.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗