[BUG] Chat history not persisting for projects on mapped drives / OneDrive

Open 💬 39 comments Opened Dec 15, 2025 by michalekz

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?

Environment

OS: Windows 11 ARM64
VS Code: 1.107.0 (also tested with 1.106.2)
Claude Code Extension: 2.0.46
Project location: Mapped drive O: pointing to OneDrive folder

Summary
Claude Code extension fails to persist chat history when the project is located on a mapped Windows drive (e.g., O:\OneDrive\Projects\...). The same project works correctly when opened from a local path (e.g., C:\temp\project).
Symptoms

Chat history disappears: After restarting VS Code, the chat title briefly appears (~1 second) then vanishes. "Past Conversations" shows empty.
Empty .jsonl files created: The extension creates empty (0 bytes) session files in ~/.claude/projects/ on every startup:

63f5f607-d84c-477d-b6b2-ff2b9243b937.jsonl 0 bytes
d733edbc-d2df-4a34-b90d-870bfc870158.jsonl 0 bytes
...

Console errors:

ERR [UriError]: Scheme contains illegal characters.
ERR chatParticipant must be declared in package.json: claude-code
ERR Error providing chat sessions: TypeError: Cannot read properties of undefined (reading 'created_at')
Root Cause Analysis
The mapped drive letter O: appears to be interpreted as a URI scheme by VS Code/extension, causing the UriError: Scheme contains illegal characters error.
Additionally, the extension creates empty .jsonl session files which then break the session loading logic (attempting to read created_at from empty/invalid JSON).

What Should Happen?

Chat history should persist across VS Code restarts regardless of whether the project is on a local drive or mapped drive.

Error Messages/Logs

Steps to Reproduce

  1. Map a network drive or OneDrive folder to a drive letter (e.g., O:)
  2. Create/open a project on that mapped drive: code O:\Projects\myproject
  3. Open Claude Code sidebar and start a conversation
  4. Close VS Code completely
  5. Reopen VS Code with the same project
  6. Observe: Chat history briefly appears then disappears

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

1.107.0

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

VS Code integrated terminal

Additional Information

Workaround
Open the project using a local path instead of the mapped drive:
bash# Instead of:
code O:\OneDrive\Projects\myproject

Use:

code C:\Users\username\OneDrive\Projects\myproject
Additional Notes
VS Code 1.107.0 Compatibility Issue
With VS Code 1.107.0, there's an additional error:
ERR Error providing chat sessions: TypeError: Cannot read properties of undefined (reading 'created_at')
This error originates from mainThreadChatSessions.ts:498 (VS Code internal code), suggesting a Chat Participant API incompatibility. Downgrading to VS Code 1.106.2 reduces (but doesn't eliminate) the errors for mapped drive projects.
Empty File Creation Bug
The extension should either:

Not create empty .jsonl files, OR
Handle empty files gracefully when loading sessions (skip them instead of crashing)

File System Monitoring Evidence
Using PowerShell FileSystemWatcher, observed that:

Extension creates new session files on every startup
Some files remain at 0 bytes
Deleting empty files temporarily fixes history loading, but new empty files are created immediately

Suggested Fixes

Path handling: Normalize Windows mapped drive paths before using them as identifiers or in URI construction
Empty file handling: Add null/empty check when parsing .jsonl session files
VS Code 1.107.0: Update Chat Participant API integration for compatibility

View original on GitHub ↗

39 Comments

github-actions[bot] · 7 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/8515
  2. https://github.com/anthropics/claude-code/issues/12872
  3. https://github.com/anthropics/claude-code/issues/9713

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

michalekz · 7 months ago

Update: Root cause identified
After extensive debugging, the actual root cause is Windows Junction points, not the mapped drive itself.
Setup:

O:\Projects was a Junction pointing to O:\OneDrive\Projects
Opening project via junction path: code O:\Projects\_optimai\euronaradi → broken history
Opening project via real path: code O:\OneDrive\Projects\_optimai\euronaradi → works fine

Solution:
Removed the junction and moved the folder directly to O:\Projects. Chat history now persists correctly, even with VS Code 1.107.0.
Bug behavior:
When a project is opened through a Windows Junction, Claude Code:

Creates empty (0 bytes) .jsonl session files in ~/.claude/projects/
These empty files break session loading (causing created_at error)
Chat history briefly appears on startup, then disappears

Suggested fix:
Resolve junction/symlink paths to their real targets before using them as project identifiers or for session storage paths.

JeffKwasha · 6 months ago

Same basic problem happens on linux with symlinks:

lrwxrwxrwx 1 jk jk 14 Nov 15 11:15 NAME -> /mnt/@/NAME/

2026-01-07 11:28:42.900 [warning] Failed to load sessions from /home/jk/NAME/NAME-worker-js: Error: ENOENT: no such file or directory, scandir '/home/jk/.claude/projects/-home-jk-NAME-NAME-worker-js'

So when writing to .claude/projects the vscode extension uses the fully resolved absolute path of '/mnt/@/SUBVOLUME/..projects..'

But when attempting to load the same project it uses the unresolved /home/USER/SYMLINK_TO_SUBVOLUME/... to look up the history

This is a very simple bugfix.

github-actions[bot] · 5 months ago

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

RhysBlackbeard · 4 months ago

Adding another data point from #26815 — same issue occurs with Google Drive for Desktop virtual drives (H:\) on Windows 11.

When the virtual drive is temporarily unavailable (Google Drive disconnects), Claude Code silently falls back to C:\Windows as the CWD. This means:

  • New sessions get stored under C--Windows project directory instead of the correct one
  • --resume can't find any previous sessions (looks in wrong directory)
  • No error message is shown — it just silently fails

The fix that would help all mapped/virtual drive users: show an error when the CWD path doesn't exist or can't be resolved, instead of silently falling back.

NerdyGriffin · 4 months ago

Root Cause Analysis (v2.1.69)

Traced through the minified extension code to identify the exact mismatch:

Write path (CLI)

When the CLI creates a session, it uses the literal cwd (e.g., A:\MyProject) to compute the project directory name via IG(), which replaces non-alphanumeric chars with -:

A:\MyProject → A--MyProject

Sessions are stored in ~/.claude/projects/A--MyProject/.

Read path (VS Code extension)

When the extension lists sessions, it calls ks() which runs fs.realpath() before computing the directory name. On Windows, realpath resolves mapped/subst drives to their actual paths:

A:\MyProject → \\server\share\MyProject  (mapped drive)
Z:\MyRepo    → D:\git\MyRepo             (subst drive)

Then IG() produces a completely different directory name:

\\server\share\MyProject → --server-share-MyProject
D:\git\MyRepo            → D--git-MyRepo

The extension looks in a directory that doesn't exist and returns zero sessions.

Code path (extension.js)

listSessions() → gP({dir: this.cwd}) → ps() → Xs(dir)
  → ks(dir)           // calls fs.realpath() — resolves mapped/subst drives
  → IG(resolvedPath)   // replaces non-alphanumeric with "-"
  → ys(result)         // joins with projects base dir
  → pq()              // readdir on non-existent dir → returns undefined
  → returns []         // no sessions found

Suggested fix

Both the CLI and extension should normalize paths the same way. Either both use realpath or neither does.

Workaround

Create a directory junction so the extension's resolved path points to the existing sessions:

  1. Determine the extension's resolved path:
  • For mapped drives (A:\\server\share): fs.realpath returns UNC path
  • Run IG() mentally: replace all non-[a-zA-Z0-9] with -
  • UNC \\server\share\Project--server-share-Project (note: double leading dash from \\)
  1. Create the junction:
New-Item -ItemType Junction `
  -Path "$HOME\.claude\projects\--server-share-Project" `
  -Target "$HOME\.claude\projects\A--Project"

Confirmed working on Windows Server with Samba/SMB mapped drives.

NerdyGriffin · 4 months ago

It's weird that this issue seems to come-and-go between updates of VS Code and/or updates of the Claude Code extension. I had this issue a week or two ago, then it seemed to go away on it's own, then it started doing it again today.

I'm not sure if that's helpful information, but I figured I might as well add it

dfliss · 4 months ago

Workaround: Windows Junction

Root cause: fs.promises.realpath() resolves mapped drive paths (e.g. X:\MyFolder\Project) to their UNC equivalents (\SERVER\Share\MyFolder\Project). The session loader uses realpath to derive the project directory name, but session files were originally saved using the drive letter path. This creates a mismatch:

  • Save path: {configDir}/projects/X--MyFolder-Project/
  • Load path: {configDir}/projects/--SERVER-Share-MyFolder-Project/ (does not exist)

Fix: Create a Windows junction linking the expected UNC-based directory name to the actual drive-letter-based directory:

# 1. Find your config dir (check CLAUDE_CONFIG_DIR env var, default is ~/.claude)
# 2. Determine the expected directory name:
node -e "const fs=require('fs').promises;(async()=>{const r=await fs.realpath('YOUR_MAPPED_DRIVE_PATH');console.log(r.normalize('NFC').replace(/[^a-zA-Z0-9]/g,'-'))})()"
# 3. Find the actual directory name in {configDir}/projects/ (the one with your conversations)
# 4. Create the junction:
New-Item -ItemType Junction -Path '{configDir}\projects\{expected-name}' -Target '{configDir}\projects\{actual-name}'

Past Conversations dropdown works immediately after creating the junction.

BenNewman100 · 4 months ago

Upvote the OP, if you want Antropic to actually fix it.

They don't even have a human look at these git hub issues unless they pass a certain upvote threshold.

WCEngineer · 4 months ago

Additional finding: DFS environments break junction workaround across workstations

The junction workaround from my earlier comment has an additional failure mode in DFS (Distributed File System) environments.

The problem

GetFinalPathNameByHandleW (the Win32 API behind Node.js fs.realpathSync) resolves DFS paths through to the underlying target server, not just the DFS namespace. The target server can differ per workstation depending on DFS referrals.

Example with drive I: mapped to \domain.com\DFSRoot\Folder:

| Workstation | GetFinalPathNameByHandle resolves to | Sanitized directory name |
|---|---|---|
| Server A | \server-a.domain.com\Share\Scripts | --server-a-domain-com-Share-Scripts |
| Server B | \server-b.domain.com\Share$\Scripts | --server-b-domain-com-Share--Scripts |

Same mapped drive, same DFS path, but different kernel-resolved paths → different session directories on each machine.

Win32_LogicalDisk.ProviderName (WMI) only returns the DFS namespace path (\domain.com\DFSRoot\Folder), which is stable across workstations. But that's not what Node.js uses.

Workaround update

The junction workaround needs to cover all three path variants:

  1. Drive letter (CLI): I--Scripts
  2. Kernel-resolved UNC (VS Code realpathSync): --server-a-domain-com-Share--Scripts
  3. DFS namespace (some contexts): --domain-com-DFSRoot-Folder-Scripts

Must be re-run on each workstation since the kernel-resolved path varies.

Suggested fix (for the extension)

Both the CLI and extension should normalize to the same path. Using the DFS namespace path (from Win32_LogicalDisk.ProviderName or equivalent) would be more stable than realpathSync in DFS environments, since it doesn't vary with DFS referral targets. Alternatively, normalize both sides through realpathSync consistently.

BoostlyPeter · 4 months ago

Adding a confirmed root cause and fix for the mapped drive case (separate from the junction/symlink angle raised by @michalekz and @JeffKwasha).

For mapped drives specifically, the root cause is in IS(v) / FS(z) in the VS Code extension — the function that normalises workspace paths before computing the session directory hash:

// Current — uses fs/promises (async):
async function IS(v) {
  try { return (await N3.realpath(v)).normalize("NFC") }
  catch { return v.normalize("NFC") }
}

fs.promises.realpath() on Windows resolves mapped drive letters to their UNC equivalent (e.g. O:\Projects\server\share\Projects). The session directory hash is then computed from the UNC path, which doesn't match the directory the CLI created using the drive-letter path. listSessions() returns 0 results — the sessions exist on disk but can't be found.

Fix: swap to fs.realpathSync() (sync require("fs") variant), which does not resolve mapped drives to UNC:

// v2.1.76 (b2 = require("fs"), already in scope):
async function IS(v) {
  try { return b2.realpathSync(v).normalize("NFC") }
  catch { return v.normalize("NFC") }
}

Confirmed working on v2.1.76 — listSessions() immediately returns correct results, session history restores on VS Code restart.

---

On the junction/symlink issue (@michalekz, @JeffKwasha): that's a related but separate inconsistency — write vs read using different resolution strategies. The realpathSync fix above would help junction points too (since realpathSync resolves junctions to their target), but only if the CLI and extension both use the same resolution. Worth tracking separately.

On the empty 0-byte .jsonl files: that's also a separate bug — the session loading code crashes on created_at from invalid JSON rather than skipping or deleting the corrupt file. Probably worth a separate issue.

See #34125 and #33140 for more detail on the mapped drive / UNC fix.

BoostlyPeter · 4 months ago

Update for v2.1.78: The function was renamed and variables changed again. New targets:

// v2.1.78 — function renamed pP, async fs = M3, sync fs = Iq:
async function pP(z) {
  try { return Iq.realpathSync(z).normalize("NFC") }
  catch { return z.normalize("NFC") }
}

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.

BoostlyPeter · 3 months ago

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 |

// v2.1.79:
async function hP(z) {
  try { return Iq.realpathSync(z).normalize("NFC") }
  catch { return z.normalize("NFC") }
}

The function has been renamed in every minor release since v2.1.76. The fix pattern is always the same — swap the async fs/promises call for the sync fs equivalent that's already in scope.

BoostlyPeter · 3 months ago

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 hP but changed both fs variable names (M3F3, IqbW). Confirmed patched and working across 11 user accounts (v2.1.74, v2.1.76, v2.1.81), 0 failures.

BenNewman100 · 3 months ago
Adding a confirmed root cause and fix for the mapped drive case (separate from the junction/symlink angle raised by @michalekz and @JeffKwasha). For mapped drives specifically, the root cause is in IS(v) / FS(z) in the VS Code extension — the function that normalises workspace paths before computing the session directory hash: // Current — uses fs/promises (async): async function IS(v) { try { return (await N3.realpath(v)).normalize("NFC") } catch { return v.normalize("NFC") } } fs.promises.realpath() on Windows resolves mapped drive letters to their UNC equivalent (e.g. O:\Projects\server\share\Projects). The session directory hash is then computed from the UNC path, which doesn't match the directory the CLI created using the drive-letter path. listSessions() returns 0 results — the sessions exist on disk but can't be found. Fix: swap to fs.realpathSync() (sync require("fs") variant), which does not resolve mapped drives to UNC: // v2.1.76 (b2 = require("fs"), already in scope): async function IS(v) { try { return b2.realpathSync(v).normalize("NFC") } catch { return v.normalize("NFC") } } Confirmed working on v2.1.76 — listSessions() immediately returns correct results, session history restores on VS Code restart. On the junction/symlink issue (@michalekz, @JeffKwasha): that's a related but separate inconsistency — write vs read using different resolution strategies. The realpathSync fix above would help junction points too (since realpathSync resolves junctions to their target), but only if the CLI and extension both use the same resolution. Worth tracking separately. On the empty 0-byte .jsonl files: that's also a separate bug — the session loading code crashes on created_at from invalid JSON rather than skipping or deleting the corrupt file. Probably worth a separate issue. See #34125 and #33140 for more detail on the mapped drive / UNC fix.

Hello Claude,

The gap in your solution is... Claude's code is not open source..... we can't patch it (or rather it's not practical to do so)

further

The function name is changing because it's minified/compiled javascript not the original source.

If I am missing something obvious let me know, but your comments are a lot of words that doesn't really say much.

BoostlyPeter · 3 months ago

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 |

// v2.1.83:
async function KT(K) {
  try { return WN.realpathSync(K).normalize("NFC") }
  catch { return K.normalize("NFC") }
}

Note: v2.1.83 also changed the function parameter from z to K, 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.

NerdyGriffin · 3 months ago

Suggestion: Label should include [area:vscode], and possibly [platform:vscode]

label:area:vscode

TheColonel2688 · 3 months ago

@BoostlyPeter is being down voted because he is letting claude write slop comments with out reviewing them to see if they add value. (I have been guilty of it too in the past)

BoostlyPeter · 3 months ago

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 |

// v2.1.87:
async function Oh(K) {
  try { return uv.realpathSync(K).normalize("NFC") }
  catch { return K.normalize("NFC") }
}

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.

RetroLoom · 3 months ago

Still experiencing this issue as of April 2026 on Windows 11 Pro with the VSCode extension.

Project is on a Samba share mapped to a Windows drive letter. Session files are being written correctly to ~/.claude/projects/ and are confirmed present on disk, but the VSCode extension shows zero conversation history in the sidebar for this project. History works fine on projects located on local drives.

This has been happening across dozens of sessions over multiple months with no workaround. The data exists — it's purely a display/lookup failure in the extension.

Please prioritize this fix. Network-mounted drives are a common workflow on Windows and this makes conversation history completely unusable for those projects.

arthurgailes · 3 months ago

Also experiencing this on shared network drives. I'll note that using the terminal interface solve the bug.

Ectropy · 3 months ago

Still occurring on 4 April 2026.
Workarounds:

  • Move your projects to a non-network drive, e.g. C:\Projects
  • Open the project folder via the UNC e.g. \\EctropyNAS\Projects

Don't use a mapped network drive. =(

This is a regression because mapped network drive used to work fine for me ~1 month ago.

AleksiAleksiev · 3 months ago

Confirming this isn't OneDrive-specific — same failure mode with a plain SUBST'd drive on Windows 11.

Setup

  • Physical path: D:\VersionControl\Git\<repo>
  • Exposed as Y:\Git\<repo> via a persistent SUBST. (I create it through HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices so it survives reboots — subst alone doesn't persist.)
  • WMI reports Y: as DriveType=3 (Local Fixed Disk), NTFS — i.e. it looks like a normal local drive to most APIs.

Symptoms across the three surfaces, all opening the same workspace:

  • CLI (launched from Y:\...): writes and reads under ~/.claude/projects/Y--Git-.... Internally consistent, history persists.
  • VS Code extension: writes new session .jsonl files under Y--Git-..., but on reload looks under D--VersionControl-Git-... and shows empty Past Conversations. So the extension can't see threads it just created — write-path and read-path are resolving the cwd differently within the same process.
  • Desktop app: only ever uses D--VersionControl-Git-....

Net effect: two project folders for one workspace, and the VS Code extension is internally inconsistent on top of that.

This points at the path-normalization layer rather than anything OneDrive-specific — any virtual/mapped drive letter (SUBST, net use, OneDrive, junction-mounted volume) will hit it.
A fix that canonicalizes the workspace path once (e.g. fs.realpath) before deriving the project-folder identifier, and uses that same canonical form on both write and read, should cover all of these cases.

TheColonel2688 · 3 months ago

Up vote the op then.

That is the only way Anthropic will notice and fix it

On Fri, Apr 17, 2026, 9:07 AM AleksiAleksiev @.***>
wrote:

AleksiAleksiev left a comment (anthropics/claude-code#14088) <https://github.com/anthropics/claude-code/issues/14088#issuecomment-4268229624> Confirming this isn't OneDrive-specific — same failure mode with a plain SUBST'd drive on Windows 11. Setup - Physical path: D:\VersionControl\Git<repo> - Exposed as Y:\Git<repo> via a persistent SUBST. (I create it through HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices so it survives reboots — subst alone doesn't persist.) - WMI reports Y: as DriveType=3 (Local Fixed Disk), NTFS — i.e. it looks like a normal local drive to most APIs. Symptoms across the three surfaces, all opening the same workspace: - CLI (launched from Y:...): writes and reads under ~/.claude/projects/Y--Git-.... Internally consistent, history persists. - VS Code extension: writes new session .jsonl files under Y--Git-..., but on reload looks under D--VersionControl-Git-... and shows empty Past Conversations. So the extension can't see threads it just created — write-path and read-path are resolving the cwd differently within the same process. - Desktop app: only ever uses D--VersionControl-Git-.... Net effect: two project folders for one workspace, and the VS Code extension is internally inconsistent on top of that. This points at the path-normalization layer rather than anything OneDrive-specific — any virtual/mapped drive letter (SUBST, net use, OneDrive, junction-mounted volume) will hit it. A fix that canonicalizes the workspace path once (e.g. fs.realpath) before deriving the project-folder identifier, and uses that same canonical form on both write and read, should cover all of these cases. — Reply to this email directly, view it on GitHub <https://github.com/anthropics/claude-code/issues/14088?email_source=notifications&email_token=ACCZEXYC2L5SFIKMO7STDID4WIUBXA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIMRWHAZDEOJWGI2KM4TFMFZW63VHMNXW23LFNZ2KKZLWMVXHJLDGN5XXIZLSL5RWY2LDNM#issuecomment-4268229624>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/ACCZEXZRQLHA56GN2JPLYGL4WIUBXAVCNFSM6AAAAACPD55AHOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DENRYGIZDSNRSGQ> . You are receiving this because you commented.Message ID: @.***>
simisae · 2 months ago

+1, hitting this exact issue. Adding another data point to support keeping this open.

Environment

  • Windows 11 desktop + laptop, both with Claude Code VS Code extension v2.1.140
  • Workspace folder on a Synology NAS, accessed via mapped drive Z:\
  • Office PC: SMB mapping \\MyNAS\MyShareZ:\
  • Home PC: RaiDrive (Synology protocol over HTTPS) → Z:\
  • ~/.claude symlinked to Z:\work\.claude so memory/settings/sessions are shared between both PCs

Symptom

  • Sessions visible in sidebar's "Local" tab during the active VS Code session
  • After VS Code restart, the list is empty for the project, even though .jsonl files are intact in ~/.claude/projects/<encoded>/
  • Persists across CLI 2.1.109 → 2.1.140

Workarounds I tested (none worked)

  1. Created C:\work\Z:\work\ symlink and opened the workspace via C:\work\... to fake out the path encoding. The extension still called realpath() and saved the session under Z--work-.... Renaming that folder to z--work-..., c--work-..., or C--work-... did not make the sidebar enumerate them on restart.
  2. Verified .jsonl content is correct, with cwd:"Z:\\work\\..." recorded inside.

Same path-normalization smell as the OP
Same logical project accumulated 7+ different "project folders" over time due to inconsistent path representations:

  • z--work-<project>
  • c--work-<project>
  • c--<project> (no work prefix)
  • y--work-<project> (Y drive era)
  • --MyNAS-MyShare-work-<project> (UNC encoded)
  • etc.

Some ~/.claude/ide/*.lock files also contain workspaceFolders with mangled paths like z:\\MyShare\\work\\<project> (drive letter spliced with the UNC share name). Points to inconsistent path normalization in the extension, exactly as the OP described.

Note on related issues
#33140, #37923, #31219, #31787 all describe the same root cause but are closed and locked. This one is the only one still open. Please don't auto-close — the bug is not resolved as of 2.1.140.

Why this matters
Blocks the use case of "shared ~/.claude on NAS for cross-PC session continuity," which is a natural multi-machine workflow. The data is technically shared — the UI just can't see it.

RetroLoom · 2 months ago

I can't believe this is still bugged. I know someone is probably going to chime in and tell me to quit complaining about this bug, but it is becoming a deal breaker for me. If claude terminal didn't have its own short comings with working in VS then it might be fine, but these production gaps are real and I don't see any attempts for anthropic to improve them. I literally cannot work on projects consistently when I cannot pull open previous conversations in my projects. Enough ranting, but seriously this is a major issue.

arthurgailes · 2 months ago
I can't believe this is still bugged. I know someone is probably going to chime in and tell me to quit complaining about this bug, but it is becoming a deal breaker for me. If claude terminal didn't have its own short comings with working in VS then it might be fine, but these production gaps are real and I don't see any attempts for anthropic to improve them. I literally cannot work on projects consistently when I cannot pull open previous conversations in my projects. Enough ranting, but seriously this is a major issue.

No, keep complaining. Anthropic won't fix it unless it stays near the top.

tom-wernham · 1 month ago

I also have exactly this issue, as of v 2.1.170. UNC workaround noted above works, but this is not satisfactory as introduces other issues (e.g. with interactive R terminal)

Nuwisam · 1 month ago

fix-network-sessions.md
this is my workaround for the issue - nevertheless I hope this gets fixed soon

Sawtaytoes · 28 days ago
fix-network-sessions.md this is my workaround for the issue - nevertheless I hope this gets fixed soon

My Claude ended up creating a SessionStart hook that needs to be added to each machine, but it fixes it with junction points (hardlinks in Windows):

~/.claude/settings.json

  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node",
            "args": [
              "C:\\Users\\USERNAME\\.claude\\hooks\\fix-mapped-drive-sessions.js"
            ],
            "timeout": 15,
            "statusMessage": "Healing session history on mapped drives"
          }
        ]
      }
    ]
  },

fix-mapped-drive-sessions.js

#!/usr/bin/env node
// SessionStart hook: heal Claude Code session history on Windows mapped network
// drives (and SUBST/symlinked workspace roots).
//
// WHY THIS EXISTS
// ---------------
// The Claude Code CLI writes session transcripts to a project folder named from
// the LITERAL cwd:           g:\Projects\X  ->  ~/.claude/projects/g--Projects-X
// The VSCode extension lists sessions from a folder named from realpath(cwd),
// which dereferences a mapped drive to its UNC target:
//                            g:\Projects\X  ->  \\srv\Share\Projects\X
//                                           ->  ~/.claude/projects/--srv-Share-Projects-X
// The two names differ, so the picker reads a non-existent folder and shows zero
// chats even though they exist. Known upstream bug (anthropics/claude-code #14088,
// #31219, closed NOT_PLANNED). The extension is a closed/minified build, so there
// is no source to patch -- this hook applies the supported workaround automatically.
//
// WHAT IT DOES
// ------------
// If realpath(cwd) encodes to a different project-folder name than the literal
// cwd, it creates a directory junction  <realpath-name>  ->  <literal-name>  so
// the extension's lookup lands on the real data. Idempotent, ~no-op on local
// drives, never deletes or overwrites real directories.
// See memory: mapped-drive-session-history-fix.
'use strict';
const fs = require('fs');
const os = require('os');
const path = require('path');
const { execFileSync } = require('child_process');

function log(msg) { process.stderr.write('[fix-mapped-drive-sessions] ' + msg + '\n'); }

try {
  if (process.platform !== 'win32') process.exit(0);

  const cwd = process.cwd();
  let real;
  try { real = fs.realpathSync.native(cwd); } catch { process.exit(0); }
  if (!real || real === cwd) process.exit(0); // local drive, nothing to do

  // Extension's project-folder encoder (Kv): non-alphanumerics -> '-'.
  // The >200-char hash branch is rare; skip it rather than guess the hash.
  const SV = 200;
  const enc = (p) => p.replace(/[^a-zA-Z0-9]/g, '-');
  const litName = enc(cwd);
  const realName = enc(real);
  if (litName.length > SV || realName.length > SV) process.exit(0);
  if (litName === realName) process.exit(0);

  const projects = path.join(os.homedir(), '.claude', 'projects');
  const litDir = path.join(projects, litName);   // where the CLI writes
  const realDir = path.join(projects, realName); // where the extension reads

  // Only act if the CLI's real data folder exists.
  if (!fs.existsSync(litDir)) process.exit(0);

  // If the target already exists, leave it alone (could be a real dir with its
  // own data, or our junction already in place).
  if (fs.existsSync(realDir)) process.exit(0);

  // mklink /J <link> <target>  (junction; no admin rights required)
  execFileSync('cmd.exe', ['/c', 'mklink', '/J', realDir, litDir], { stdio: 'ignore' });
  log('linked ' + realName + ' -> ' + litName);
} catch (e) {
  // Never block session start on a failure here.
  log('skipped: ' + (e && e.message ? e.message : String(e)));
}
process.exit(0);

It worked for me without even having to restart VSCode.

I lost so many tokens and chats to this. I'm glad I finally found a per-machine workaround.

Armnum · 27 days ago

I can confirm this bug is still present in VSCode extension v2.1.181 (June 2026).

My environment

  • OS: Windows 11 Pro (10.0.26100)
  • VSCode extension: 2.1.181
  • Workspace location: Network share \\SRV001\Dati\Server\... mapped as Z:\
  • Model: Claude Sonnet 4.5 via AWS Bedrock (eu-central-1)

Symptoms

  1. Sessions appear in sidebar but are empty when opened
  • All sessions show generic title "Claude Code" instead of actual conversation names
  • Clicking on a session shows completely empty conversation (no messages)
  1. Session files exist and are NOT empty
  • All 73 .jsonl session files are present in ~/.claude/projects/Z--MASTER-...
  • Files contain full conversation data (verified with manual inspection)
  • File sizes range from 16KB to 25MB
  1. CLI works perfectly
  • claude --resume correctly lists all 73 sessions with proper titles
  • Opening sessions from CLI shows full conversation history
  • All data is intact and accessible via terminal

What I tried (did NOT work)

  • Created a .bat file to force VSCode to always open workspace with the mapped drive path (Z:\) instead of UNC path
  • Result: sessions still appear empty in VSCode extension

Root cause hypothesis

The VSCode extension appears unable to properly read session metadata when the workspace is on a mapped network drive, even though:

  • The session files physically exist
  • The files are correctly formatted
  • The CLI can read them without issues

This suggests the bug is specific to the VSCode extension's file handling with network-mapped drives, not a data corruption or path resolution issue.

Impact

This makes the VSCode extension essentially unusable for users working with network-based workspaces. The only workaround is switching to CLI (claude --resume), which is less intuitive for non-technical users.

Hope this bug gets prioritized — it's been open since December 2025 and affects many users working in enterprise environments with network shares.

BasedGPT · 27 days ago

What you've traced as the URI-scheme error is the downstream symptom; the upstream cause is a path mismatch in how the CLI and the VS Code extension derive the project slug from your cwd.

When your workspace is at O:\OneDrive\Projects\myproject, the CLI writes session transcripts to ~/.claude/projects/O--OneDrive-Projects-myproject/ using the literal drive letter. The VS Code extension calls fs.realpathSync on the cwd before encoding it, which dereferences O: back to the physical path (something like C:\Users\username\OneDrive\Projects\myproject) and reads from (and writes stub files to) C--Users-username-OneDrive-Projects-myproject/ instead. Two slug directories for the same workspace, and the extension can only see the one it wrote to.

The empty .jsonl files on every startup are the extension's stubs in the realpath-derived folder. Any content the CLI wrote lives in the drive-letter slug — worth checking ~/.claude/projects/ for a folder starting with O-- to see if sessions with actual content are there.

I built a toolkit for diagnosing this split: diagnose.py in BasedGPT/claude-code-session-recovery maps both directories and shows which transcripts have content versus which are empty stubs. If CLI sessions exist in the O--... folder, recover_vscode_sessions.py can read those transcripts and rebuild the VS Code session cache (state.vscdb).

For future sessions, the junction hook @Sawtaytoes shared above addresses the root cause directly: it creates a Windows directory junction so the extension's realpath lookup finds the CLI's data automatically. Running diagnose.py first gives you the picture of what's already there before applying any fix.

Hope this helps, if my tools are able to help you, would appreciate a ⭐ :)

ktremain · 27 days ago

Cross-linking to keep two distinct failure modes from getting conflated here.

This issue's original report is the write-side / OneDrive case (0-byte .jsonl files +
UriError: Scheme contains illegal characters). There's a separate read-side variant —
transcripts exist with data, but the sidebar shows only the current session — tracked
in #63527 / #34125: the extension's listSessions() calls async realpath(), which resolves
mapped drives to their UNC path, so it reads a non-existent project folder and silently
returns []. Still reproducing on v2.1.183, including DFS/SASE-mapped drives. Detailed
root-cause + one-call-site fix in #63527.

Armnum · 27 days ago

Hi Karl!
Thank you for your advice.
I'll keep you update if your tool will work also for me, as soon as I have
my my hands on my system, because at the moment I'm out for a commission.
Thanks a lot.
Francesco

Il ven 19 giu 2026, 10:23 BasedGPT @.***> ha scritto:

BasedGPT left a comment (anthropics/claude-code#14088) <https://github.com/anthropics/claude-code/issues/14088#issuecomment-4749812522> What you've traced as the URI-scheme error is the downstream symptom; the upstream cause is a path mismatch in how the CLI and the VS Code extension derive the project slug from your cwd. When your workspace is at O:\OneDrive\Projects\myproject, the CLI writes session transcripts to ~/.claude/projects/O--OneDrive-Projects-myproject/ using the literal drive letter. The VS Code extension calls fs.realpathSync on the cwd before encoding it, which dereferences O: back to the physical path (something like C:\Users\username\OneDrive\Projects\myproject) and reads from (and writes stub files to) C--Users-username-OneDrive-Projects-myproject/ instead. Two slug directories for the same workspace, and the extension can only see the one it wrote to. The empty .jsonl files on every startup are the extension's stubs in the realpath-derived folder. Any content the CLI wrote lives in the drive-letter slug — worth checking ~/.claude/projects/ for a folder starting with O-- to see if sessions with actual content are there. I built a toolkit for diagnosing this split: diagnose.py in BasedGPT/claude-code-session-recovery maps both directories and shows which transcripts have content versus which are empty stubs. If CLI sessions exist in the O--... folder, recover_vscode_sessions.py can read those transcripts and rebuild the VS Code session cache (state.vscdb). For future sessions, the junction hook @Sawtaytoes <https://github.com/Sawtaytoes> shared above addresses the root cause directly: it creates a Windows directory junction so the extension's realpath lookup finds the CLI's data automatically. Running diagnose.py first gives you the picture of what's already there before applying any fix. Hope this helps, if my tools are able to help you, would appreciate a ⭐ :) — Reply to this email directly, view it on GitHub <https://github.com/anthropics/claude-code/issues/14088?email_source=notifications&email_token=BCG35YMRKL4P6P7SNUYADJT5AT2BNA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTINZUHE4DCMRVGIZKM4TFMFZW63VHMNXW23LFNZ2KKZLWMVXHJLDGN5XXIZLSL5RWY2LDNM#issuecomment-4749812522>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/BCG35YIMVEOTEJG7CYL4P7L5AT2BNAVCNFSNUABFKJSXA33TNF2G64TZHM4TGNZSGUZTINZVHNEXG43VMU5TGNZTGIZDMNZSGI22C5QC> . Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS <https://github.com/notifications/mobile/ios/BCG35YMO47GLEKHPW6HBZOT5AT2BNA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTINZUHE4DCMRVGIZKM4TFMFZW63VHMNXW23LFNZ2KKZLWMVXHJKTGN5XXIZLSL5UW64Y> and Android <https://github.com/notifications/mobile/android/BCG35YN4ELZHMZ4KS6DWCTD5AT2BNA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTINZUHE4DCMRVGIZKM4TFMFZW63VHMNXW23LFNZ2KKZLWMVXHJLTGN5XXIZLSL5QW4ZDSN5UWI>. Download it today! You are receiving this because you commented.Message ID: @.***>
Armnum · 26 days ago

@BasedGPT @ktremain Thank you both for the detailed analysis and clarifications!

Confirming the variant: Read-side issue

@ktremain is correct — my case is the read-side variant described in #63527:

  • ✅ Transcript files exist with full data (not 0-byte)
  • ✅ Files are in correct format and readable
  • ❌ VSCode sidebar shows empty or only current session
  • listSessions() returns [] because it dereferences mapped drive to non-existent UNC path

What I tried with @BasedGPT's tools:

1. Diagnosis with diagnose.py:

  • Confirmed the path mismatch issue
  • Found 3 separate project folders for the same workspace:
  • Z--MASTER-...: 80 sessions (CLI using literal drive letter)
  • --SRV001-...: 7 sessions (VSCode dereferencing to UNC path)
  • D--MASTER-...: 0 sessions (old local path)

2. Session unification:

  • Moved all 7 sessions from --SRV001 to Z--MASTER
  • Total: 90 sessions now in a single folder
  • Verified no UUID duplicates

3. Manual cache rebuild attempt:

  • Since recover_vscode_sessions.py expects pre-populated cache (mine was completely empty), I created a custom script
  • Extracted titles from all 90 .jsonl files
  • Populated agentSessions.model.cache in VSCode's state.vscdb
  • Cache successfully written (verified: 90 entries, ~18KB JSON)

The problem persists: VSCode overwrites the cache

Timeline:

  • 13:03 — Custom script writes 90 sessions to cache ✅
  • 13:06 — User creates new chat in VSCode
  • 13:25:57 — VSCode extension overwrites cache back to []

Root cause (confirming @ktremain's analysis):

When creating a new session, the extension:

  1. Calls listSessions() to refresh the sidebar
  2. listSessions() uses realpath() which dereferences Z:\\SRV001\...
  3. Looks for sessions in --SRV001-... folder (now empty after unification)
  4. Finds nothing → returns []
  5. Writes empty array to cache, overwriting the manually rebuilt cache

This creates a cycle: even if you manually populate the cache, VSCode erases it on the next session creation because listSessions() can't find the files (looking in wrong path).

Current workaround confirmed:

CLI (claude --resume) works perfectly — correctly finds all 90 sessions with proper titles. The bug is isolated to VSCode extension's realpath() dereferencing behavior.

Cross-reference to #63527

Based on @ktremain's pointer, this is clearly the read-side variant tracked in #63527. The one-call-site fix mentioned there (preventing realpath() from dereferencing mapped drives in listSessions()) would likely resolve this completely.

Environment details:

  • OS: Windows 11 Pro (10.0.26100)
  • VSCode extension: v2.1.181
  • Workspace: Network share \\SRV001\... mapped as Z:\
  • Confirmed behavior: listSessions()realpath() → UNC path → non-existent folder → []

Thank you both for the diagnostic tools and the clear separation of the two bug variants. The tools were invaluable for confirming the exact failure mode!

BasedGPT · 25 days ago

@Armnum So glad it was helpful mate, thanks for the update and the detailed write up. If you think it earned it, would appreciate a star! Will update my tooling to help others with the same problems in the future.

Necmttn · 25 days ago

The durable key should be the canonical workspace identity, not whichever path form one caller saw.

For mapped drives and OneDrive, I would store both raw cwd and resolved path, then derive one canonical project key after normalization. Session metadata should include the transcript directory it expects, and the sidebar should be able to rebuild from JSONL if IndexedDB/session metadata points at the wrong slug.

Also treat 0-byte JSONL as a recoverable corrupt record. Skip it with a warning rather than letting one stub break the whole session list.

---

_Generated with ax._

amasover · 12 days ago

Adding a variant I don't see covered in this thread (or in #63527 / #34125 / #33140): the same empty-history failure with no drive letter involved at all — workspace opened directly as the root of an SMB share (\\server\share\). Still present in extension 2.1.200.

Why it's relevant to the fix being discussed: in this variant the lister's fs.promises.realpath has nothing to dereference (no mapped drive, no junction, no DFS). It merely drops the trailing separator of the share root, and that alone breaks the lookup:

  • The writer keys the project folder from process.cwd(), which keeps the separator for a share root: \\server\share\ → sanitized --server-share- (trailing dash).
  • The lister (listSessions) normalizes through fs.promises.realpath → libuv → GetFinalPathNameByHandleW, which returns share roots without the separator: \\server\share--server-share. That folder doesn't exist → silent empty list.

Queried the Win32 API directly to confirm the asymmetry — it only affects UNC roots, which is why local folders (and even a C:\ root workspace) are fine:

| Input | GetFinalPathNameByHandleW result |
|---|---|
| C:\ | \\?\C:\ (separator kept) |
| \\server\share\ | \\?\UNC\server\share (separator dropped) |

Transcripts on disk are valid and non-empty with the correct "cwd": "\\\\server\\share\\" recorded — no 0-byte files involved, so the empty list doesn't require the corrupt-stub angle in this variant.

Implication for the one-call-site fix tracked in #63527: if the fix only special-cases drive-letter dereferencing, share roots stay broken. Normalizing writer and lister through the same function fixes both variants — e.g. the JS-implementation fs.realpathSync preserves the root's trailing separator (verified: returns \\server\share\), matching what the writer produces.

Workaround (verified — history and resume fully restored): same junction trick as earlier in this thread, just one dash apart:

New-Item -ItemType Junction `
  -Path   "$env:USERPROFILE\.claude\projects\--server-share" `
  -Target "$env:USERPROFILE\.claude\projects\--server-share-"

Environment: VS Code extension 2.1.200 (win32-x64), Windows 11 Pro build 26100; transcripts written by 2.1.195 were equally affected.

zhalker · 10 days ago

I asked Claude Fable to fix the extension and he did, faster than the developers could read this issue :)