VS Code extension: Past conversations dropdown broken due to cached rejected promise in B3.refresh()
Bug Description
The VS Code extension's "Past Conversations" dropdown never shows previous sessions. Only the currently active conversation is visible. The claude --resume CLI command works correctly, confirming session files are valid.
Root Cause
In extension.js, the B3 class (session storage) has a promise-chaining bug in the refresh() method:
class B3 {
refreshing = Promise.resolve(); // starts resolved
refresh() {
return this.refreshing = this.refreshing.then(
async () => this.performRefresh()
), this.refreshing;
}
async performRefresh() {
let v = Az(this.projectRoot);
let z = await fs.promises.readdir(v); // scandir - fails with ENOENT if dir doesn't exist yet
// ...
}
}
The sequence:
- Extension starts and calls
B3.load(this.cwd)at startup (without await) - This creates a
B3instance, caches it inB3.cache, and callsrefresh() performRefresh()callsreaddir()on~/.claude/projects/<project-dir>- If the project directory doesn't exist yet (first time opening this workspace with Claude),
readdir()throwsENOENT this.refreshingbecomes a rejected promise- All subsequent
refresh()calls chain.then()on the rejected promise - the fulfilled handler is never executed (.then()skips the callback on rejected promises) - The
B3instance is cached forever inB3.cache, so it's never recreated - Result:
listSessions()always returns empty, dropdown shows nothing
Even after the directory IS created (by the first conversation), the cached B3 instance remains stuck with a rejected promise chain.
Evidence from Logs
2026-02-18 17:02:46.679 [warning] Failed to load sessions from /path/to/project: Error: ENOENT: no such file or directory, scandir '~/.claude/projects/-project-dir'
// Directory created at 17:04:39 by first session, but subsequent calls still fail:
2026-02-18 17:05:28.330 [warning] Failed to load sessions from /path/to/project: Error: ENOENT: no such file or directory, scandir '~/.claude/projects/-project-dir'
Suggested Fix
Option A - Recover from previous failures in the promise chain:
refresh() {
return this.refreshing = this.refreshing
.catch(() => {}) // recover from previous rejection
.then(async () => this.performRefresh()),
this.refreshing;
}
Option B - Ensure the directory exists before calling readdir():
async performRefresh() {
let v = Az(this.projectRoot);
await fs.promises.mkdir(v, { recursive: true }); // ensure dir exists
let z = await fs.promises.readdir(v);
// ...
}
Workaround
Fully quit VS Code (Cmd+Q) and reopen it. As long as the project directory already exists in ~/.claude/projects/, the initial readdir() will succeed and sessions will load correctly.
Environment
- Claude Code Extension: 2.1.45
- VS Code: macOS (darwin-arm64)
- OS: macOS Sequoia 15.3
Steps to Reproduce
- Open a new workspace in VS Code that has never been used with Claude Code before
- The
~/.claude/projects/<project-dir>directory does not exist yet - Start a Claude conversation (this creates the directory and session file)
- End the conversation and start a new one
- Click the "Past Conversations" dropdown - no previous sessions shown
- Run
claude --resumein terminal - previous sessions ARE shown (proves data is fine)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗