claude.json corrupted by concurrent writes (no atomic write / file locking)

Resolved 💬 3 comments Opened Feb 26, 2026 by mattgaffin Closed Feb 26, 2026

Bug

~/.claude/claude.json gets corrupted when multiple claude processes run concurrently. The file ends up truncated (partial JSON), causing "JSON Parse error: Unexpected EOF" on next startup.

Environment

  • Claude Code v2.1.59
  • Windows 11 Pro (Git Bash / MINGW64)
  • Multiple claude -p subprocesses running via scheduled automation (cron-style jobs that invoke claude -p for background tasks)

Reproduction

  1. Have 2+ claude processes running concurrently (e.g., a foreground session + a claude -p background invocation)
  2. Both processes read/write claude.json (growth book features, client data cache, tool usage stats, etc.)
  3. The file gets truncated mid-write, producing invalid JSON

This happens reliably when concurrent processes exist. In my case, scheduled background jobs spawn claude -p subprocesses, and when two overlap they corrupt the shared config.

Evidence

227 corrupted backups in ~/.claude/backups/ over ~6 days. Corruption clusters at times when multiple processes run:

  • 68 corruptions in a single minute (1:58 AM, during scheduled batch processing)
  • Corrupted files range from 0 bytes to ~5.9 KB (full valid file is ~5.9 KB)
  • The smallest corrupted files (77-306 bytes) are clearly truncated mid-write -- valid JSON start, sudden EOF
  • Some "corrupted" backups are actually complete valid JSON (the detection/backup mechanism fires even on valid files sometimes)

Example of a truncated file (123 bytes):

{
  "cachedGrowthBookFeatures": {
    "tengu_session_memory": false
  },
  "clientDataCache": {
    "data": {},

Root Cause

The config writer does a non-atomic write (open, truncate, write). When two processes write simultaneously:

  1. Process A opens + truncates the file
  2. Process B opens + truncates the file (now 0 bytes)
  3. Process A writes its data
  4. Process B writes its data, overwriting A's partial output
  5. Either process may produce a truncated result

Suggested Fix

Use atomic writes: write to a temp file (claude.json.tmp), then rename() to claude.json. On POSIX this is atomic; on Windows, use os.replace() or equivalent. Optionally add advisory file locking for the read-modify-write cycle.

This is a standard pattern for config files that may be accessed by concurrent processes.

Workaround

Manually restoring from the largest .corrupted backup file in ~/.claude/backups/ works, but the corruption recurs on the next concurrent access.

View original on GitHub ↗

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