Local sessions list empty for workspaces on a mapped network drive (native realpath != session-write path on Windows)

Status Open
Reported on v2.1.210
Maintainer reply None cached
Activity 3 comments · opened Jul 17, 2026

Version: 2.1.210 (VSCode extension), Windows 11

Summary

When a VSCode workspace is opened on a mapped network (SMB) drive (e.g. Z:\ mapped to \\SERVER\share), the Local sessions tab always shows "No sessions yet", even though sessions exist and claude --resume from a terminal lists/loads them fine.

Root cause

Sessions are stored under ~/.claude/projects/<encoded-cwd>/. There's an inconsistency in how the cwd is resolved:

  • Session writer / CLI: uses the raw cwd Z:\ → fs.realpathSync('Z:\\') returns Z:\ → folder Z--. Sessions are written here.
  • Extension session lister (listSessions → Gse): resolves the path with fs.realpathSync.native(), which on Windows resolves the mapped drive to its UNC target \\SERVER\share → folder --SERVER-share. This folder doesn't exist, so readdir throws and the list is empty.

Reproduction of the divergence:

fs.realpathSync('Z:\\')          // => 'Z:\\'                 (folder Z--)
fs.realpathSync.native('Z:\\')   // => '\\\\SERVER\\share'    (folder --SERVER-share)

Steps to reproduce

  1. Map a network share to a drive letter (net use Z: \\SERVER\share).
  2. Open Z:\ as a VSCode workspace, run a Claude Code session.
  3. Session file is written under ~/.claude/projects/Z--/.
  4. Open the Sessions panel → Local → "No sessions yet" (CLI claude --resume from Z:\ shows it correctly).

Impact

All local session history is invisible in the extension UI for any workspace on a mapped network drive.

Suggested fix

Use the same path-resolution strategy for listing as for writing (avoid realpathSync.native for the projects-folder key, or apply the same resolution in both places).

Workaround

Junction the folder the lister expects to the real one:

mklink /J "%USERPROFILE%\.claude\projects\--SERVER-share" "%USERPROFILE%\.claude\projects\Z--"

View original on GitHub ↗

3 Comments

XxSp1derxX · 2 months ago

Confirming this on 2.1.220 (VS Code extension, Windows 11) — still present. Two things worth adding, since I ran into it independently and dug through the current bundle.

1. It reproduces without any network share.

Every report on this so far involves SMB, which makes it look like a niche NAS problem. A plain subst drive triggers the identical split, so this needs no server to test:

subst T: C:\some\dir
node -e "const fs=require('fs');console.log('sync :',fs.realpathSync('T:\\'));fs.promises.realpath('T:\\').then(r=>console.log('async:',r))"
# sync : T:\
# async: C:\some\dir
subst T: /d

Anything that makes GetFinalPathNameByHandle return something other than what the JS resolver returns lands here — mapped drives, subst, and presumably junctioned workspace roots.

2. In 2.1.220 the call is the async fs.promises.realpath, not realpathSync.native.

The lister path is listSessions() → Pme() → LIt() → DIt() → ife(), where ife() is:

async function ife(e){ try { return Wd(await Lo.realpath(e)) } catch { return Wd(e) } }  // Lo = fs.promises

Same effect — Node's async realpath is uv_fs_realpath → GetFinalPathNameByHandle — but the identifier changed, so grepping the current bundle for realpathSync.native finds nothing. The writer side still resolves via the sync JS realpathSync (in Dme()), which is where the divergence comes from.

Everything downstream of the readdir is innocent: I replayed the _b → cfe → XRt/afe chain against real transcripts, and every session passes the filters with correct titles. It fails purely on readdir of a directory that was never created.

Workaround caveat. The mklink /J workaround in the issue body works on 2.1.220 — junctions for 7 projects, and the Local list populates correctly for them in the UI. One warning for anyone applying it: remove the junction with cmd /c rmdir <link> — Remove-Item -Recurse in PowerShell 5.1 deletes through the junction and takes the real transcripts with it.

obskeep · 1 month ago

Still true for 2.1.228, samme issue here.

gonetra · 1 month ago

Still present on VS Code extension 2.1.270 (win32-x64), Windows 11 Pro 10.0.26200. Adding details from a fresh investigation, since the issue is marked stale and #93342 was closed as a duplicate of this one.

Setup: every workspace has H:\redigo as its first folder, where H: is a mapped SMB drive (\\fileserver\vhosts). 431 transcripts (1.6 GB) live under ~/.claude/projects/h--redigo/, all with "entrypoint":"claude-vscode" and "cwd":"h:\\redigo". The Sessions panel shows nothing for them; a workspace on C: lists fine.

Where the split is in 2.1.270 (extension.js, names as minified in that build):

  • Lister: buildSessionList() → Lb$({dir: cwd}) → TK0 → CK0 → z = await Gt(dir) where Gt is F6(await K8.realpath($)) with K8 = require("fs/promises"). YL(z) then probes only projects/<key(z)>.
  • Writer: Fb$ → fs.realpathSync(path) (JS implementation).

On this machine, in the extension host's Node:

fs.realpathSync('h:/redigo')            // 'h:\\redigo'                    -> key  h--redigo   (where the files are)
await fs.promises.realpath('h:/redigo') // '\\\\fileserver\\vhosts\\redigo' -> key  --fileserver-vhosts-redigo (does not exist)

So YL gets ENOENT on the only directory it checks and returns []. No error is logged; the extension log only shows the restore_declined line followed by an empty list, exactly as described in #93342.

The CLI side is not affected. Zero-cost check (pointing ANTHROPIC_BASE_URL at a closed port and reading the SessionStart hook type in the debug log): claude -p x --continue --no-session-persistence run from H:\<project> resumes the latest transcript (SessionStart:resume) both with the npm CLI 2.1.272 and with the extension's bundled resources/native-binary/claude.exe 2.1.270. So the same session store is readable by the CLI binaries; only the in-process lister of the extension host misses it.

Side effect worth knowing: the panel still lists the claude.ai remote (Remote Control) mirror of each session, with the same title as the invisible local one. Clicking it triggers a teleport that fetches 0 events and creates an empty 97-byte local session ({"type":"teleported-from",...,"messageCount":0}), so the user ends up with an empty tab named like the real conversation.

Suggested fix is the same as the OP: derive the project key for listing with the same resolution used for writing (drive-letter path, no native realpath), or probe both keys.