[BUG] VS Code extension 2.1.280 (Windows): symlinked session transcripts silently dropped from the session list
Environment
- Claude Code VS Code extension 2.1.280 (win32-x64)
- Windows 11 Pro 10.0.26200
- Worked in 2.1.220
Summary
Session transcripts under ~/.claude/projects/<project>/ that are symbolic links no longer appear in the session list. There is no error and no log line; the files are intact and readable.
We keep shared conversations as one real .jsonl in one project folder, with symlinks to it in the other project folders, so the same conversation is available in every workspace. After updating to 2.1.280, 15 of the 19 sessions in one workspace disappeared from the list — exactly the 15 symlinked ones.
Root cause
The session-file reader gained symlink hardening. On POSIX it opens with O_NOFOLLOW; on Windows, where that flag is not available, it falls back to an lstat check (2.1.280, minified):
var pC$ = process.platform === "win32"
? O_RDONLY
: O_RDONLY | O_NOFOLLOW | O_NONBLOCK;
async function $b(file, …) {
…
if (pC$ === O_RDONLY) { if (!(await fs.lstat(file)).isFile()) return null }
…
}
lstat() does not follow the link, so isFile() is false for every symlink and the transcript is treated as unreadable. It is dropped in the per-session read of the listing, before any title or cwd logic runs.
Repro
- Pick a session in
%USERPROFILE%\.claude\projects\<A>\, move its.jsonlto%USERPROFILE%\.claude\projects\<B>\. - Link it back (Developer Mode or elevated shell):
mklink "%USERPROFILE%\.claude\projects\<A>\<id>.jsonl" "%USERPROFILE%\.claude\projects\<B>\<id>.jsonl"
- Open workspace A → the session is missing from the list. 2.1.220 lists it.
Expected
Follow symlinks that resolve to a regular file inside the projects directory — or, at minimum, log that a transcript was skipped. A silent disappearance looks like data loss to the user.
Suggested fix
Accept a symlink only when its resolved target is a regular file inside <config dir>/projects (CLAUDE_CONFIG_DIR or ~/.claude), and keep rejecting everything else, so the hardening still holds.
Note that the read and write paths are currently inconsistent on Windows: the append path's no-follow flag is 0 on win32, so renaming a symlinked session appends to its target fine, while reading it is refused.
Workaround
We patch exactly that check (P12_follow in install.js): https://github.com/tonicheval/claude-plugin-enhancer — with it, all 19 sessions list again, and symlinks pointing outside the projects directory are still rejected.
Related (same setup)
With the new auto-archive, the archive list is global (hiddenSessionIds) while session groups are stored per workspace. A session visible in several workspaces is therefore archived by the sweep of any workspace where it is not grouped, which hides it everywhere and removes it from its group in the other workspaces.