[BUG] VS Code extension: Session History empty / generic "Claude Code" title, despite valid .jsonl files with resolvable titles on disk — non-deterministic over time
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?
Across several sibling project folders (subfolders of one parent directory, each its own VS Code workspace / ~/.claude/projects/<slug> bucket), the Claude Code panel shows either the tab title stuck on the generic "Claude Code" instead of a resolved session title, or the Session History panel empty/"no session yet" — even though the corresponding bucket directory contains valid .jsonl session files with resolvable customTitle/aiTitle fields.
Critically, the failure is non-deterministic over time for an UNCHANGED file: a session that worked normally (listed, opened, resumed live) in 4 sibling buckets later failed in a 5th bucket with no file change whatsoever (same size, same mtime) between the successful and failed observations. This rules out a per-file/per-data cause and points to a race condition or transient internal state in the extension (e.g. session-list/title-cache population), not a data or configuration problem.
What Should Happen?
Each project's Session History panel should reliably reflect the .jsonl files physically present in that project's ~/.claude/projects/<slug>/ directory, with titles resolved from customTitle/aiTitle/lastPrompt/summary, consistently across window reloads and over time — not vary for an unchanged file.
Error Messages/Logs
Extension output channel (Claude VSCode.log) shows no error correlated with the failures — only benign [WARN]/[DEBUG] lines (missing settings.local.json, missing managed-settings.json, non-POSIX consent-store canonicalization).
One warning found during the initial investigation that may be relevant:
[WARN] [event-loop-stall] — up to 9.4s of event-loop blocking observed
notification channel error: Received a response for an unknown message ID
VS Code DevTools console: no JS error correlated with clicking the failing sessions. The failure is completely silent — no exception surfaced anywhere in the UI or logs.
Neither ~/.claude/sessions-index.json nor ~/.claude/history.jsonl exists on this machine, so whatever indexing mechanism this version uses is not either of those two (older, undocumented) files referenced in issues #29331 and #60610.
Steps to Reproduce
- Create a working folder whose bucket (~/.claude/projects/<slug>/) contains 3 .jsonl sessions copied from elsewhere (same sessionIds as their origin bucket), roughly 8 MB, 34 MB, and 150 MB in size.
- Open VS Code on this folder with the Claude Code extension.
- Observe that typically only the mid-sized session appears in Session History and opens correctly; the other two don't appear, or open a blank tab.
- Reopen the same bucket in a fresh VS Code window at a later time (different day/session): the previously-working mid-sized session can now also fail (Session History shows "no session yet"), with zero file changes in between (verified via file size and mtime).
Additional diagnostics already run, all negative (did not resolve or explain the issue):
- File integrity check: all sessions are valid line-by-line JSON, structurally identical, no corruption.
- Patched extension.js's hardcoded loadTimeoutMs/initializeTimeoutMs from 60000ms to 300000ms locally — no effect.
- claude doctor (CLI): clean, but this is an installation-level check (PATH, binary location) identical regardless of project folder — not project-scoped, doesn't inspect session indexing.
- /doctor (in-session, full pass): clean — no CLAUDE.md conflicts, no invalid settings JSON, no duplicate installs, no hooks. Does not audit session-history indexing either.
- Reload Window and full VS Code restart: no change.
- Folder/slug computation independently re-verified correct; Windows drive-letter casing confirmed irrelevant (NTFS case-insensitive); VS Code shortcut targets confirmed correct; .gitignore/git-tracking status confirmed irrelevant.
Claude Model
Not sure / Multiple models
Is this a regression?
Yes, this worked in a previous version
Last Working Version
Unclear exact version — first observed already broken on v2.1.237; the non-deterministic "worked, then failed" transition happened within that same version, not across an update.
Claude Code Version
2.1.239 (Claude Code) — native binary, commit 9bf8e9521fe0. First observed on v2.1.237.
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Other
Additional Information
VS Code integrated terminal
Related existing (closed, unresolved) issues describing the same pattern on VS Code/Windows:
- #29331 — "sessions-index.json severely out of sync — only 3 of 61 sessions indexed, older sessions invisible in UI" (platform:vscode, platform:windows)
- #60610 — "sessions missing from history dropdown, not indexed in history.jsonl"
Official docs (sessions.md) confirm that hand-copying a .jsonl session file across project directories is unsupported for cross-project --resume lookups ("a hand-copied duplicate makes Claude Code report not-found rather than resume an arbitrary copy"), but this doesn't fully explain our case: the non-deterministic failure of an UNCHANGED, non-duplicated file argues for an underlying indexing/timing bug independent of the duplication itself.
Happy to provide: full Claude VSCode.log excerpts from multiple restart attempts, directory listings of the affected buckets, and the local extension.js timeout-patch diff, on request.
Minimal reproduction script (synthetic data only, no real content)
Generates 3 dummy .jsonl session files at the same sizes as the original report (~8/34/150 MB) with valid session-record structure (customTitle in tail, etc.), duplicated across sibling "project bucket" folders the way ~/.claude/projects/<slug>/ works — reproduces the file-size/duplication conditions without exposing any real data.
# Reproduction script for: Session History empty / generic "Claude Code" title
# Generates synthetic .jsonl session files (no real content) matching the sizes involved
# in the original report (~8 MB, ~34 MB, ~150 MB), and duplicates them across sibling
# "project bucket" folders the way ~/.claude/projects/<slug>/ directories work.
#
# Usage: powershell -ExecutionPolicy Bypass -File repro_session_history_bug.ps1 -OutDir "C:\path\to\test-buckets"
param(
[string]$OutDir = "$env:TEMP\claude-session-history-repro"
)
function New-DummySession {
param(
[string]$Path,
[string]$SessionId,
[string]$FakeCwd,
[string]$TitleText,
[long]$TargetBytes
)
$lines = New-Object System.Collections.Generic.List[string]
# Head: minimal valid session opening (mirrors real Claude Code session structure)
$lines.Add((@{ type = "queue-operation"; operation = "enqueue"; timestamp = "2026-01-01T00:00:00.000Z"; sessionId = $SessionId } | ConvertTo-Json -Compress))
$lines.Add((@{ parentUuid = $null; isSidechain = $false; type = "user"; message = @{ role = "user"; content = @(@{ type = "text"; text = "dummy first prompt for repro" }) }; uuid = [guid]::NewGuid().ToString(); sessionId = $SessionId } | ConvertTo-Json -Compress -Depth 5))
$headBytes = ([System.Text.Encoding]::UTF8.GetByteCount(($lines -join "`n")))
$tailReserve = 4096 # room for the tail block appended after padding
# Padding: repeated dummy assistant lines to reach the target size
$filler = (@{ type = "assistant"; sessionId = $SessionId; message = @{ role = "assistant"; content = @(@{ type = "text"; text = ("x" * 400) }) } } | ConvertTo-Json -Compress -Depth 5)
$fillerLineBytes = [System.Text.Encoding]::UTF8.GetByteCount($filler) + 1
$remaining = $TargetBytes - $headBytes - $tailReserve
$count = [Math]::Max(0, [Math]::Floor($remaining / $fillerLineBytes))
$writer = New-Object System.IO.StreamWriter($Path, $false, [System.Text.Encoding]::UTF8)
foreach ($l in $lines) { $writer.WriteLine($l) }
for ($i = 0; $i -lt $count; $i++) { $writer.WriteLine($filler) }
# Tail: last-prompt + custom-title, matching the real title-resolution fields
$writer.WriteLine((@{ type = "last-prompt"; lastPrompt = "dummy last prompt"; sessionId = $SessionId } | ConvertTo-Json -Compress))
$writer.WriteLine((@{ type = "custom-title"; sessionId = $SessionId; customTitle = $TitleText } | ConvertTo-Json -Compress))
$writer.Close()
}
# Three sessions matching the original report's sizes, all sharing the same "parent cwd" metadata
$sessions = @(
@{ Id = "11111111-1111-1111-1111-111111111111"; Title = "Dummy Session A (150MB)"; Bytes = 150MB },
@{ Id = "22222222-2222-2222-2222-222222222222"; Title = "Dummy Session B (8MB)"; Bytes = 8MB },
@{ Id = "33333333-3333-3333-3333-333333333333"; Title = "Dummy Session C (34MB)"; Bytes = 34MB }
)
# Simulate the parent bucket + N sibling sub-buckets, each receiving a full copy of all 3 sessions
$buckets = @("parent-bucket", "sub-bucket-1", "sub-bucket-2", "sub-bucket-3")
foreach ($bucket in $buckets) {
$bucketPath = Join-Path $OutDir $bucket
New-Item -ItemType Directory -Force -Path $bucketPath | Out-Null
foreach ($s in $sessions) {
$filePath = Join-Path $bucketPath "$($s.Id).jsonl"
New-DummySession -Path $filePath -SessionId $s.Id -FakeCwd $bucket -TitleText $s.Title -TargetBytes $s.Bytes
Write-Host "Created $filePath ($('{0:N1}' -f ((Get-Item $filePath).Length / 1MB)) MB)"
}
}
Write-Host ""
Write-Host "Done. To reproduce: copy each '$OutDir\<bucket>' folder's content into a real"
Write-Host "~/.claude/projects/<slug>/ directory for a test VS Code workspace, open that workspace,"
Write-Host "and check whether Session History lists all 3 dummy sessions correctly across bucket folders"
Write-Host "and over repeated window reloads."