[BUG] VS Code extension session history empty on Windows when project is on mapped network drive (fs.realpath resolves to UNC, breaking project-key hash)
Summary
On Windows, when a project folder lives on a mapped network drive (e.g. X: mapped to \\server\share), the Claude Code VS Code extension's "past conversations" clock icon shows no sessions. The .jsonl session files exist on disk and claude --resume from a terminal lists them correctly. The extension's list_sessions_request returns an empty array; clicking the clock then spawns a fresh session (extension log: launch_claude ... resume: undefined), which effectively clobbers the current scrollback.
Root cause
The extension's cwd-normalizer calls fs.realpath(cwd).normalize("NFC"). On Windows, fs.realpath resolves mapped network drives to their UNC targets. So X:\myproject becomes \\server\share\myproject. The extension's project-key hasher (str.replace(/[^a-zA-Z0-9]/g, "-")) then produces --server-share-myproject instead of X--myproject. The claude.exe native binary creates ~/.claude/projects/X--myproject/ using the drive-letter form, so the extension's lookup never matches the actual on-disk directory. The directory resolver returns undefined and listSessions returns [].
Reproduced deterministically:
> python -c "import os; print(os.path.realpath('X:\\myproject'))"
\\server\share\myproject
Whereas claude.exe on the same cwd writes to ~/.claude/projects/X--myproject/.
Repro
- On Windows, map a network drive:
net use X: \\192.168.1.100\share - Create a project folder on the drive:
mkdir X:\myproject - Open
X:\myprojectin VS Code with the Claude Code extension - Have at least one conversation to create a session
- Close VS Code fully, reopen
- Click the clock icon → no sessions shown
- Terminal
claude --resumein the same folder → sessions listed correctly
Expected
Clock icon lists past sessions. Same behavior as on C: or on non-mapped paths.
Actual
Empty list. Clicking clock spawns a fresh session, visually clobbering the current scrollback.
Affected versions
Confirmed in 2.1.112 and 2.1.113 (latest as of 2026-04-17). The vulnerable code is minified but identifiable by this pattern, unchanged between the two versions apart from symbol renames:
async function <fn>(K){try{return(await <fs>.realpath(K)).normalize("NFC")}catch{return K.normalize("NFC")}}
In 2.1.112 this is named up using fs alias W3; in 2.1.113 it is Gl using fs alias M3.
Suggested fix
Any one of:
- Skip
realpathon Windows. Cheapest fix; makes the extension matchclaude.exe's behavior:
``js``
async function up(K){
if (process.platform === "win32") return K.normalize("NFC");
try { return (await W3.realpath(K)).normalize("NFC") }
catch { return K.normalize("NFC") }
}
- Apply
realpathconsistently inclaude.exetoo, so the write and read paths agree. - Add a fallback in the directory resolver: if
readdir(Kq4(K))fails, scan~/.claude/projects/*/and match by reading a.jsonl's embeddedcwdfield.
Local workaround
Patching extension.js with the if (process.platform === "win32") short-circuit in the vulnerable function fixes the issue on 2.1.112. I have a pattern-based re-apply script that survives version bumps; happy to share if useful.
Related (different root causes)
- #22215 — cross-project cache contamination on macOS (open)
- #18619 — sessions-index.json not updating
- #31787 — VS Code + Desktop simultaneous use on Windows (closed as duplicate)
None of the above reference mapped network drives or the realpath/UNC interaction. This appears to be a new variant specific to Windows + mapped drives.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗