UNC path issue

Status Open
Reported on v2.1.222
Maintainer reply None cached
Activity 0 comments · opened Aug 5, 2026

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.realpath and fs.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) }
`
→ transcripts land in
~/.claude/projects/--dfsalias-Share-path-to-repo/`.

  • 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.realpath and fs.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) }
`
→ transcripts land in
~/.claude/projects/--dfsalias-Share-path-to-repo/`.

  • 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.realpath and fs.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) }
`
→ transcripts land in
~/.claude/projects/--dfsalias-Share-path-to-repo/`.

  • 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_

View original on GitHub ↗