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

  1. Start Claude Code on Windows
  2. Run any workflow that spawns multiple subagents via Task tool (e.g., parallel research tasks)
  3. Exit Claude Code
  4. 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.json is 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 userID field 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

  1. Reduce write frequency: Batch config updates instead of writing on every field change
  2. Windows-safe file locking: Use proper-lockfile or OS-level advisory locks instead of the current mechanism that fails with EPERM
  3. 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)
  4. Separate auth state: Store oauthAccount and critical auth fields in a separate file that is written infrequently, rather than in the heavily-written .claude.json

Workaround Attempted

  • Restoring oauthAccount from backup before launch (via wrapper script) — did not resolve the login issue, suggesting Claude Code checks additional state beyond just the presence of oauthAccount
  • Setting .claude.json as 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.

View original on GitHub ↗

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