UNC path issue
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
VSCode extension: session list always empty on DFS-alias / namespace UNC workspaces (realpath mismatch between writer and reader)
Extension version: 2.1.222 (win32-x64)
Platform: Windows 10 Enterprise 19045
Workspace path: a UNC path whose host is a DFS namespace alias, e.g. \\dfsalias\Share\path\to\repo, where dfsalias resolves to a different real server name.
Symptom
The local session list in the VSCode extension is always empty. Only sessions that are currently open show up (those live in webview memory). After closing a chat or restarting VSCode, it is unreachable from the UI.
Transcripts are written correctly the whole time — nothing is lost. This is purely a lookup failure.
Root cause
Writer and reader derive the project-directory key with two different realpath implementations, which disagree on Windows UNC paths:
fs.realpathSync(Node's JS implementation) keeps the DFS alias host.fs.promises.realpathandfs.realpathSync.native(native binding) resolve to the real server name.
Measured on the affected machine for workspace \\dfsalias\Share\path\to\repo:
| implementation | result | project dir | outcome |
|---|---|---|---|
| fs.realpathSync | \\dfsalias\Share\path\to\repo | --dfsalias-Share-path-to-repo | 13 .jsonl files |
| fs.promises.realpath | \\realserver.example.local\Share\path\to\repo | --realserver-example-local-Share-path-to-repo | ENOENT |
| fs.realpathSync.native | \\realserver.example.local\Share\path\to\repo | same as above | ENOENT |
In extension.js (2.1.222):
- The write/session-key path uses the JS variant:
``js`
function Zme(e){ let t=Xt.resolve(e??"."), r; try{ r=az.realpathSync(t) }catch{ r=t } return Zd(r) }
~/.claude/projects/--dfsalias-Share-path-to-repo/`.
→ transcripts land in
- The session-enumeration path uses the promises variant:
``js`
async function gfe(e){ try{ return Zd(await Uo.realpath(e)) }catch{ return Zd(e) } }
gfe()
feeds Tb() → zIt() → readdir, which throws ENOENT and is swallowed, so Tb() returns [] and listSessions()` yields 0 sessions.
The empty result then reaches the webview, whose doListSessions() has nothing to iterate — so the list renders empty while open channels remain visible.
Verification
Patching gfe() to use the same implementation as the writer fixes it immediately. Instrumenting listSessions() with a log of this.cwd and the result count:
before: [listSessions] cwd="\\dfsalias\Share\path\to\repo" found=0 workspaceFolders=["\\dfsalias\Share\path\to\repo"]
after: [listSessions] cwd="\\dfsalias\Share\path\to\repo" found=13 workspaceFolders=["\\dfsalias\Share\path\to\repo"]
Local workaround (lost on every extension update):
async function gfe(e){ try{ return Zd(require("fs").realpathSync(e)) }catch{ try{ return Zd(await Uo.realpath(e)) }catch{ return Zd(e) } } }
Suggested fix
Use one single path-canonicalization helper for both writing and reading the project key. Since Zme() (which determines where transcripts are written) uses fs.realpathSync, gfe() should do the same — otherwise any environment where the two implementations disagree silently loses access to its history.
Alternatively, make Tb() fall back to the non-canonicalized and/or natively-resolved key when the primary directory does not exist, so a mismatch degrades instead of returning an empty list.
Secondary finding
The first listSessions() call after activation runs before VSCode reports its workspace folders:
[listSessions] cwd="C:\Users\<user>" found=0 workspaceFolders=[]
this.cwd is computed as fs.realpathSync(workspaceFolders[0] ?? os.homedir()), so it falls back to the home directory and queries the wrong project. Harmless in effect (later calls use the correct cwd), but it creates a stray empty --C--Users-<user> directory under ~/.claude/projects/.
What Should Happen?
VSCode extension: session list always empty on DFS-alias / namespace UNC workspaces (realpath mismatch between writer and reader)
Extension version: 2.1.222 (win32-x64)
Platform: Windows 10 Enterprise 19045
Workspace path: a UNC path whose host is a DFS namespace alias, e.g. \\dfsalias\Share\path\to\repo, where dfsalias resolves to a different real server name.
Symptom
The local session list in the VSCode extension is always empty. Only sessions that are currently open show up (those live in webview memory). After closing a chat or restarting VSCode, it is unreachable from the UI.
Transcripts are written correctly the whole time — nothing is lost. This is purely a lookup failure.
Root cause
Writer and reader derive the project-directory key with two different realpath implementations, which disagree on Windows UNC paths:
fs.realpathSync(Node's JS implementation) keeps the DFS alias host.fs.promises.realpathandfs.realpathSync.native(native binding) resolve to the real server name.
Measured on the affected machine for workspace \\dfsalias\Share\path\to\repo:
| implementation | result | project dir | outcome |
|---|---|---|---|
| fs.realpathSync | \\dfsalias\Share\path\to\repo | --dfsalias-Share-path-to-repo | 13 .jsonl files |
| fs.promises.realpath | \\realserver.example.local\Share\path\to\repo | --realserver-example-local-Share-path-to-repo | ENOENT |
| fs.realpathSync.native | \\realserver.example.local\Share\path\to\repo | same as above | ENOENT |
In extension.js (2.1.222):
- The write/session-key path uses the JS variant:
``js`
function Zme(e){ let t=Xt.resolve(e??"."), r; try{ r=az.realpathSync(t) }catch{ r=t } return Zd(r) }
~/.claude/projects/--dfsalias-Share-path-to-repo/`.
→ transcripts land in
- The session-enumeration path uses the promises variant:
``js`
async function gfe(e){ try{ return Zd(await Uo.realpath(e)) }catch{ return Zd(e) } }
gfe()
feeds Tb() → zIt() → readdir, which throws ENOENT and is swallowed, so Tb() returns [] and listSessions()` yields 0 sessions.
The empty result then reaches the webview, whose doListSessions() has nothing to iterate — so the list renders empty while open channels remain visible.
Verification
Patching gfe() to use the same implementation as the writer fixes it immediately. Instrumenting listSessions() with a log of this.cwd and the result count:
before: [listSessions] cwd="\\dfsalias\Share\path\to\repo" found=0 workspaceFolders=["\\dfsalias\Share\path\to\repo"]
after: [listSessions] cwd="\\dfsalias\Share\path\to\repo" found=13 workspaceFolders=["\\dfsalias\Share\path\to\repo"]
Local workaround (lost on every extension update):
async function gfe(e){ try{ return Zd(require("fs").realpathSync(e)) }catch{ try{ return Zd(await Uo.realpath(e)) }catch{ return Zd(e) } } }
Suggested fix
Use one single path-canonicalization helper for both writing and reading the project key. Since Zme() (which determines where transcripts are written) uses fs.realpathSync, gfe() should do the same — otherwise any environment where the two implementations disagree silently loses access to its history.
Alternatively, make Tb() fall back to the non-canonicalized and/or natively-resolved key when the primary directory does not exist, so a mismatch degrades instead of returning an empty list.
Secondary finding
The first listSessions() call after activation runs before VSCode reports its workspace folders:
[listSessions] cwd="C:\Users\<user>" found=0 workspaceFolders=[]
this.cwd is computed as fs.realpathSync(workspaceFolders[0] ?? os.homedir()), so it falls back to the home directory and queries the wrong project. Harmless in effect (later calls use the correct cwd), but it creates a stray empty --C--Users-<user> directory under ~/.claude/projects/.
Error Messages/Logs
Steps to Reproduce
VSCode extension: session list always empty on DFS-alias / namespace UNC workspaces (realpath mismatch between writer and reader)
Extension version: 2.1.222 (win32-x64)
Platform: Windows 10 Enterprise 19045
Workspace path: a UNC path whose host is a DFS namespace alias, e.g. \\dfsalias\Share\path\to\repo, where dfsalias resolves to a different real server name.
Symptom
The local session list in the VSCode extension is always empty. Only sessions that are currently open show up (those live in webview memory). After closing a chat or restarting VSCode, it is unreachable from the UI.
Transcripts are written correctly the whole time — nothing is lost. This is purely a lookup failure.
Root cause
Writer and reader derive the project-directory key with two different realpath implementations, which disagree on Windows UNC paths:
fs.realpathSync(Node's JS implementation) keeps the DFS alias host.fs.promises.realpathandfs.realpathSync.native(native binding) resolve to the real server name.
Measured on the affected machine for workspace \\dfsalias\Share\path\to\repo:
| implementation | result | project dir | outcome |
|---|---|---|---|
| fs.realpathSync | \\dfsalias\Share\path\to\repo | --dfsalias-Share-path-to-repo | 13 .jsonl files |
| fs.promises.realpath | \\realserver.example.local\Share\path\to\repo | --realserver-example-local-Share-path-to-repo | ENOENT |
| fs.realpathSync.native | \\realserver.example.local\Share\path\to\repo | same as above | ENOENT |
In extension.js (2.1.222):
- The write/session-key path uses the JS variant:
``js`
function Zme(e){ let t=Xt.resolve(e??"."), r; try{ r=az.realpathSync(t) }catch{ r=t } return Zd(r) }
~/.claude/projects/--dfsalias-Share-path-to-repo/`.
→ transcripts land in
- The session-enumeration path uses the promises variant:
``js`
async function gfe(e){ try{ return Zd(await Uo.realpath(e)) }catch{ return Zd(e) } }
gfe()
feeds Tb() → zIt() → readdir, which throws ENOENT and is swallowed, so Tb() returns [] and listSessions()` yields 0 sessions.
The empty result then reaches the webview, whose doListSessions() has nothing to iterate — so the list renders empty while open channels remain visible.
Verification
Patching gfe() to use the same implementation as the writer fixes it immediately. Instrumenting listSessions() with a log of this.cwd and the result count:
before: [listSessions] cwd="\\dfsalias\Share\path\to\repo" found=0 workspaceFolders=["\\dfsalias\Share\path\to\repo"]
after: [listSessions] cwd="\\dfsalias\Share\path\to\repo" found=13 workspaceFolders=["\\dfsalias\Share\path\to\repo"]
Local workaround (lost on every extension update):
async function gfe(e){ try{ return Zd(require("fs").realpathSync(e)) }catch{ try{ return Zd(await Uo.realpath(e)) }catch{ return Zd(e) } } }
Suggested fix
Use one single path-canonicalization helper for both writing and reading the project key. Since Zme() (which determines where transcripts are written) uses fs.realpathSync, gfe() should do the same — otherwise any environment where the two implementations disagree silently loses access to its history.
Alternatively, make Tb() fall back to the non-canonicalized and/or natively-resolved key when the primary directory does not exist, so a mismatch degrades instead of returning an empty list.
Secondary finding
The first listSessions() call after activation runs before VSCode reports its workspace folders:
[listSessions] cwd="C:\Users\<user>" found=0 workspaceFolders=[]
this.cwd is computed as fs.realpathSync(workspaceFolders[0] ?? os.homedir()), so it falls back to the home directory and queries the wrong project. Harmless in effect (later calls use the correct cwd), but it creates a stray empty --C--Users-<user> directory under ~/.claude/projects/.
Claude Model
Opus
Is this a regression?
No, this never worked
Last Working Version
_No response_
Claude Code Version
2.1.222
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
VS Code integrated terminal
Additional Information
_No response_