[Bug] Windows: Project keys split by path casing in ~/.claude.json

Status Open
Reported on v2.1.221
Maintainer reply None cached
Activity 1 comment · opened Aug 9, 2026

Bug Description
Windows: project keys in ~/.claude.json are stored with the caller's path casing, splitting one directory into multiple projects

On Windows, Claude Code keys projects in ~/.claude.json by the working-directory string as supplied, not by the filesystem's canonical casing. Launching the same directory as D:\repos\qoreai\jupyter and D:\repos\QoreAI\jupyter produces two separate project entries for one directory.

Per-project state then splits across both — hasTrustDialogAccepted, allowedTools, enabledMcpjsonServers / disabledMcpjsonServers, and session telemetry — and which set applies depends on how you happened to type the path. A directory trusted under one spelling isn't trusted under the other.

Observed on v2.1.225: 10 collision groups across 56 project entries, affecting 10 distinct directories. Reproduces immediately — a session started from the non-canonical casing re-creates its own key on shutdown even after the entries are merged.

Suggested fix: normalize the project key through the filesystem's canonical casing (fs.realpathSync.native on Windows) before reading or writing projects[...].

Detection:

python -c "
 import json,os
 d=json.loads(open(os.path.expanduser('~/.claude.json'),'rb').read().decode('utf-8-sig'))
 g={}
 for k in d['projects']: g.setdefault(k.lower(),[]).append(k)
 print({k:v for k,v in g.items() if len(v)>1})

Environment Info

  • Platform: win32
  • Terminal: windows-terminal
  • Version: 2.1.221
  • Feedback ID: 770c7bbf-8b9c-4d8f-a4e1-d1f9983f7735

Errors

[{"error":"TelemetrySafeError: VirtualMessageList: itemKeys/messages length desync (keys=202 messages=201 range=[161,202))\n    at JGS (B:/~BUN/root/src/entrypoints/cli.js:22807:8181)\n    at TKf (B:/~BUN/root/src/entrypoints/cli.js:22807:1103)\n    at Mn (B:/~BUN/root/src/entrypoints/cli.js:2713:21369)\n    at YA (B:/~BUN/root/src/entrypoints/cli.js:2713:40466)\n    at _F (B:/~BUN/root/src/entrypoints/cli.js:2713:51390)\n    at T$e (B:/~BUN/root/src/entrypoints/cli.js:2713:89052)\n    at Ske (B:/~BUN/root/src/entrypoints/cli.js:2713:87996)\n    at A$e (B:/~BUN/root/src/entrypoints/cli.js:2713:87815)\n    at JR (B:/~BUN/root/src/entrypoints/cli.js:2713:84072)\n    at it (B:/~BUN/root/src/entrypoints/cli.js:2713:6665)","timestamp":"2026-08-04T20:00:45.959Z"}]

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗