[BUG] VS Code extension: input text lost when new session initializes due to listSessions race condition
Description
When opening a new chat session in the VS Code extension, if the user starts typing in the input field immediately, the typed text is silently cleared after a few seconds. This happens because the webview re-renders the input component when listSessions() completes asynchronously, unmounting and remounting the input component and losing all typed text.
Steps to Reproduce
- Open VS Code with the Claude Code extension
- Open a new Claude Code chat panel (no previous session to restore)
- Immediately start typing a message in the input field (do not submit)
- Wait 2-5 seconds
- Observe: the input text disappears and the session appears to "reset"
Expected Behavior
Typed text in the input field should be preserved across internal re-renders and session state changes.
Actual Behavior
The input text is silently cleared after a few seconds, forcing the user to retype their message.
Root Cause Analysis
After analyzing the bundled source code (extension.js and webview/index.js), the issue is a race condition between user input and asynchronous session list loading:
Sequence of events:
- Webview boots (
fT1()inwebview/index.js):
- If no previous session ID exists,
createSession({ isExplicit: false })is called immediately (line ~244986), creating an empty session with a uniqueinternalId(viacrypto.randomUUID()) - Simultaneously,
listSessions()is called (line ~244961), which is async
- User starts typing into the input field (
Ln0component, line ~236261)
- Input text is stored only in React
useState("")(line ~236280) and DOMtextContent - No persistence to localStorage or VSCode webview state
listSessions()completes (after a few seconds):
doListSessions()(line ~166845) processes server-side sessions- If
Y(sessions changed) is true and URL contains asessionparameter (line ~166886-166889):
``js``
let U = new URLSearchParams(window.location.search).get("session");
if (U) {
let z = G.find(V => V.sessionId.value === U);
if (z) this.activeSession.value = z; // activeSession reassigned!
}
- Even without a URL session parameter,
this.sessions.value = G(line ~166885) triggers reactive effects
activeSessionchanges → the session view component (uo0) is keyed byactiveSession.value.internalId(line ~244350):
``jsx`
key: activeSession.value.internalId
internalId
A different means React **unmounts the entire component tree** (including Ln0`) and remounts it fresh
- Input text is lost because
useState("")resets to empty string on remount
Why there's no recovery:
The input component (Ln0) has no persistence layer:
- No saving to
localStorage - No saving to VSCode webview state (
acquireVsCodeApi().setState()) - No debounced backup of input text
- The
_q0state manager (line ~244921) only persistssessionIDandsessionUpdatedAt, not input text
Suggested Fix
Any of these approaches (or a combination) would fix the issue:
Option A: Persist input buffer in webview state (simplest)
In the Ln0 component, save input text to VSCode webview state on every change and restore on mount:
// On input change
vscodeApi.setState({ ...state, inputBuffer: text });
// On mount
const savedInput = vscodeApi.getState()?.inputBuffer || "";
Option B: Prevent unnecessary activeSession reassignment
In doListSessions(), skip reassigning activeSession if the current session has no sessionId (meaning the user hasn't submitted yet and is still in the input phase):
// Before reassigning activeSession, check if user might be typing
if (this.activeSession.value && !this.activeSession.value.sessionId.value
&& !this.activeSession.value.busy.value) {
// Don't reassign - user is in a fresh session, possibly typing
return;
}
Option C: Transfer input text across session switches
When activeSession changes, capture the input text from the old session's component and inject it into the new session's component via a shared ref or context.
Environment
- OS: macOS (Darwin 25.3.0, Apple Silicon)
- VS Code: Latest stable
- Claude Code Extension: v2.1.63
- Platform: darwin-arm64
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗