VS Code extension can't find sessions on mapped network drives (realpath resolves to UNC)
Status Closed — not planned
Reported on v2.1.72
Maintainer reply None cached
Workaround ✓ Mentioned in description ↑
Activity 12 comments · opened Mar 11, 2026 · closed Apr 30, 2026
Problem
On Windows, when the project lives on a mapped network drive (e.g. U:\projects\my-app), the VS Code extension's listSessions() returns no results because:
- The CLI creates session
.jsonlfiles in~/.claude/projects/u--projects-my-app/(encoded from the drive letter path) - The VS Code extension calls
fs.realpath()which resolves the mapped drive to its UNC path (\fileserver.example.com\share\projects\my-app) - The UNC path encodes to a completely different directory name (
--fileserver-example-com-share-projects-my-app) - No sessions are found ÔÇö the sidebar is empty after every restart
Impact
- All sessions created in VS Code disappear on restart
- Sessions created in the terminal CLI are never visible in VS Code
- Affects any Windows user whose workspace is on a mapped network drive (common in studios/enterprises with DFS/SMB shares)
Workaround
Create a symlink between the two directory names in ~/.claude/projects/:
mklink /D "%USERPROFILE%\.claude\projects\--fileserver-example-com-share-projects-my-app" "%USERPROFILE%\.claude\projects\u--projects-my-app"
Suggested fix
Either skip realpath() on Windows mapped drives, or normalize both the CLI and extension to use the same path before encoding the project directory name.
Environment
- Windows 10/11, Claude Code 2.1.72
- Mapped network drive (DFS/SMB)
12 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Yes, I have the same issue and I tested and confirmed this myself manually (not having Claude do it). I just used Claude to write the below report. Also these are the real paths I tests. I didn't redact them.
----
Title: VS Code Extension does not show resume session list for sessions on SMB mapped network drives
Body:
Summary
The VS Code Claude Code Extension fails to list previous sessions in the "Resume Session" picker when the working directory is on an SMB network share mapped to a drive letter. Sessions on local drives (including additional physical drives) work correctly. Sessions on the network drive are being saved to
~/.claude/projects/with correct folder names and content — they just never appear in the resume list.Environment
\\BEN-LAPTOP-MAIN\L (All My Files))Network Drive Details
L:\ is mapped to UNC path
\\BEN-LAPTOP-MAIN\L (All My Files)(note: share name contains spaces and parentheses).Test Sessions
I manually created test sessions by opening VS Code in each directory and starting a Claude Code chat. I then closed and reopened VS Code in the same directory to check if previous sessions appeared in the resume list.
| # | Working Directory | Drive Type | Resume Works? |
|---|---|---|---|
| 1 |
C:\Users\Codesys-Dev| Local (C:) | Yes || 2 |
c:\Users\Codesys-Dev\Desktop| Local (C:) | Yes || 3 |
c:\Users\Codesys-Dev\Desktop\New folder| Local (C:) | Yes || 4 |
c:\Program Files (x86)\Windows Media Player\Media Renderer| Local (C:) | Yes || 5 |
c:\This Is A Long Directory Name\...\Final Level Directory Name Here OK| Local (C:) | Yes || 6 |
l:\| SMB mapped →\\BEN-LAPTOP-MAIN\L (All My Files)| No || 7 |
l:\Repos\Professional\Experiments\HMI_Project_Refactoring_Tool| SMB mapped →\\BEN-LAPTOP-MAIN\L (All My Files)\Repos\...| No || 8 |
t:\New folder\New folder 2| Local physical (T:) | Yes |Key Observations
.jsonlfiles are being written correctly to~/.claude/projects/for all drives, including L:\. The data is there; the extension just doesn't find it.Possible Cause
The extension may be resolving the mapped drive letter to a UNC path (e.g.,
\\BEN-LAPTOP-MAIN\L (All My Files)\...) during session lookup, producing a different encoded folder name than what was used when the session was saved (which used the drive letterl:\...). Alternatively, there may be a filesystem API behavior difference on SMB shares affecting directory enumeration or file watching.Root cause: fs.realpathSync() / fs.realpath() resolve a mapped drive letter (e.g. I:\) to its UNC path (\\server\share\...). Sessions are saved under the drive-letter slug (I--Projects-...) but looked up under the UNC slug (--server-share-Projects-...), so they're never found.
Fix (tested on VS Code extension 2.1.73, Windows 11, workspace on mapped network drive):
In FS() and all realpathSync() calls — if the resolved path starts with \\ but the input started with a drive letter, return the original path:
async function FS(z) {
try {
let _r = (await d8.realpath(z)).normalize("NFC");
if (_r.startsWith("\\\\") && !z.startsWith("\\\\"))
return z.normalize("NFC");
return _r;
} catch {
return z.normalize("NFC");
}
}
Same pattern for realpathSync() in resolveSessionListView, resolveWebviewView, etc.
This fix resolved the issue on my end. Happy to provide a patch/PR if useful.
Confirmed on v2.1.76 (also v2.1.74). Same root cause —
IS(v)/FS(z)usesfs/promises.realpath()which resolves drive letters to UNC on Windows.@ROC2024-REAL's conditional check works, but there's a simpler fix: just swap to
fs.realpathSync()(the syncrequire("fs")variant) instead.realpathSyncdoes not resolve mapped drives to UNC on Windows — it returns the drive-letter path unchanged. No need to check for\prefix.The sync and async
fsvariants behave differently on Windows for mapped drives specifically:fs.promises.realpath()resolves via Win32GetFinalPathNameByHandlewhich returns UNC;fs.realpathSync()uses a different code path that preserves the drive letter.Confirmed effect:
listSessions()returns the correct count immediately (n=11in my case). Session restore works across VS Code restarts.Scope is wider than the Past Conversations dropdown — the same
IS()/FS()call is used when restoring VS Code panel tabs viadeserializeWebviewPanel. Withn=0,activateSessionFromServersilently fails and the panel stays blank on restart. Same fix resolves both symptoms.See also: #34125 (same root cause, filed last week) — I've posted the tested fix there with more detail.
Confirmed on v2.1.77 as well — your realpathSync approach is indeed cleaner. I've verified it locally:
fs.realpathSync('I:/Projets/Python/Traducteur')
// → 'I:\Projets\Python\Traducteur' ← drive letter preserved
await fs.promises.realpath('I:/Projets/Python/Traducteur')
// → '\\vsrvdatas\Informatique\Projets\...' ← UNC via GetFinalPathNameByHandle
No need for the startsWith("\\") guard — just swap the call.
I've been patching this since v2.1.72 and the main annoyance is minified names changing every release (IS→XP, v→z, N3→x3…). Here's a generic Python script that finds the right function/variables dynamically and survives version bumps. Run it after each extension update:
import re, glob
Find latest installed version
exts = glob.glob('<VSCODE_EXTENSIONS>/anthropic.claude-code-*-win32-x64')
ext_dir = sorted(exts)[-1]
print(f'Extension: {ext_dir}')
ext_js = f'{ext_dir}/extension.js'
with open(ext_js, 'r', encoding='utf-8') as f:
c = f.read()
patched = False
Detect the async realpath function (minified names vary per version)
Pattern: async function XX(p){try{return(await FS_PROMISES.realpath(p)).normalize("NFC")}catch{return p.normalize("NFC")}}
m = re.search(
r'async function (\w+)\((\w+)\)\{try\{return\(await (\w+)\.realpath\(\2\)\)'
r'\.normalize\("NFC"\)\}catch\{return \2\.normalize\("NFC"\)\}\}',
c
)
if m:
func_name, param, promises_var = m.group(1), m.group(2), m.group(3)
# Find the sync fs variable — the one already used in realpathSync calls
m_sync = re.search(r'(\w+)\.realpathSync\(\w+\[0\]\|\|\w+\.homedir\(\)\)', c)
if m_sync:
sync_var = m_sync.group(1)
old = m.group(0)
new = (
f'async function {func_name}({param})'
f'{{try{{return {sync_var}.realpathSync({param}).normalize("NFC")}}'
f'catch{{return {param}.normalize("NFC")}}}}'
)
c = c.replace(old, new)
print(f' [OK] {func_name}({param}): {promises_var}.realpath -> {sync_var}.realpathSync')
patched = True
else:
print(' [!!] Could not find sync fs variable')
else:
# Check if already patched
if re.search(r'async function \w+\(\w+\)\{try\{return \w+\.realpathSync', c):
print(' [--] Already patched')
else:
print(' [!!] async realpath function not found — pattern may have changed')
if patched:
with open(ext_js, 'w', encoding='utf-8') as f:
f.write(c)
print('Done. Restart VS Code.')
Tested across v2.1.72, v2.1.73, v2.1.76, v2.1.77 — regex picks up the right function each time.
Good callout on deserializeWebviewPanel scope — I was only tracking listSessions() but that explains the blank panel on restart.
Update for v2.1.78: The function was renamed and variables changed again. New targets:
Summary across versions:
| Version | Function | Async fs var | Sync fs var |
|---------|----------|-------------|-------------|
| v2.1.74 |
FS(z)|o8|DH|| v2.1.76 |
IS(v)|N3|b2|| v2.1.78 |
pP(z)|M3|Iq|All three sync vars are
require("fs")— already in scope. The fix pattern is identical across versions; only the names change.Update for v2.1.79: Only the function name changed again. All other variables identical to v2.1.78.
| Version | Function | Async fs var | Sync fs var |
|---------|----------|-------------|-------------|
| v2.1.74 |
FS(z)|o8|DH|| v2.1.76 |
IS(v)|N3|b2|| v2.1.78 |
pP(z)|M3|Iq|| v2.1.79 |
hP(z)|M3|Iq|The function has been renamed in every minor release since v2.1.76. The fix pattern is always the same — swap the async
fs/promisescall for the syncfsequivalent that's already in scope.Update for v2.1.81: Multiple variable changes. Updated table:
| Version | Function | Async fs var | Sync fs var |
|---------|----------|-------------|-------------|
| v2.1.74 |
FS(z)|o8|DH|| v2.1.76 |
IS(v)|N3|b2|| v2.1.78 |
pP(z)|M3|Iq|| v2.1.79 |
hP(z)|M3|Iq|| v2.1.81 |
hP(z)|F3|bW|v2.1.81 kept the function name
hPbut changed both fs variable names (M3→F3,Iq→bW). Confirmed patched and working across 11 user accounts (v2.1.74, v2.1.76, v2.1.81), 0 failures.Update for v2.1.83: Function renamed again, parameter changed, both fs variables changed.
| Version | Function | Async fs var | Sync fs var |
|---------|----------|-------------|-------------|
| v2.1.74 |
FS(z)|o8|DH|| v2.1.76 |
IS(v)|N3|b2|| v2.1.78 |
pP(z)|M3|Iq|| v2.1.79 |
hP(z)|M3|Iq|| v2.1.81 |
hP(z)|F3|bW|| v2.1.83 |
KT(K)|i1|WN|Note: v2.1.83 also changed the function parameter from
ztoK, and both the async and sync fs variable names changed. The function name, parameter, and fs variables have now all changed simultaneously — the only stable pattern across versions is the function signature shape and the.normalize("NFC")calls.Confirmed patched and working on v2.1.83 across 16 user accounts (spanning v2.1.74 through v2.1.83), 0 failures.
Update for v2.1.87: Function renamed again, all variables changed.
| Version | Function | Async fs var | Sync fs var |
|---------|----------|-------------|-------------|
| v2.1.74 |
FS(z)|o8|DH|| v2.1.76 |
IS(v)|N3|b2|| v2.1.78 |
pP(z)|M3|Iq|| v2.1.79 |
hP(z)|M3|Iq|| v2.1.81 |
hP(z)|F3|bW|| v2.1.83 |
KT(K)|i1|WN|| v2.1.87 |
Oh(K)|w3|uv|Seven versions tracked, bug still present and unfixed. Confirmed patched and working across 17 user accounts (v2.1.74 through v2.1.87), 0 failures.
Closing for now — inactive for too long. Please open a new issue if this is still relevant.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.