[BUG] deserializeWebviewPanel still discards the session ID in 2.1.220 — restored editor tabs always open blank (refs #35004)

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 1 comment · opened Aug 2, 2026

Summary

The webview panel serializer registered for claudeVSCodePanel restores the tab but never the conversation, because it discards the session ID. Every editor-area Claude tab comes back blank after a window reload, crash, or restart.

This was previously reported in #35004 (bug, has repro) and closed not planned by the stale bot on 2026-05-10 — then auto-locked with a message directing similar reports to a new issue, which is what this is. Related: #64756 (Remote-SSH reconnect, same root cause) and #60937 (feature framing), both also auto-closed as stale. None were closed on merit, and the behavior is unchanged in the current release.

Version: 2.1.220 (Anthropic.claude-code, win32-x64) — confirmed the latest published build at time of filing. VS Code on Windows 11.

Repro

  1. Open a Claude Code session in an editor tab (not the sidebar) and exchange a few messages.
  2. Reload the window (Developer: Reload Window), or kill/restart VS Code to simulate a crash.
  3. The tab is restored in the right position — and is empty. The prior conversation is not reattached.

Expected: the restored tab rehydrates the session it was showing. Actual: a fresh, empty panel.

Root cause

The extension declares onWebviewPanel:claudeVSCodePanel and registers a serializer, so VS Code correctly offers the persisted state back. But the handler reads only a layout flag and drops everything else (deminified from extension.js):

vscode.window.registerWebviewPanelSerializer("claudeVSCodePanel", {
  async deserializeWebviewPanel(panel, state) {
    let E;
    if (typeof state?.isFullEditor === "boolean") E = state.isFullEditor;
    else E = vscode.window.tabGroups.all.findIndex(g => g.viewColumn === panel.viewColumn) === 0;
    manager.setupPanel(panel, void 0, void 0, E);   // <-- session ID position is hard-coded undefined
  }
});

The receiving side already supports what's needed — setupPanel(panel, sessionId, prompt, isFullEditor) forwards argument 2 straight into the webview HTML:

setupPanel(e, t, r, n) {
  ...
  e.webview.html = this.getHtmlForWebview(e.webview, t, r, !1, n);
}

and the live path maintains the mapping (createPanel(sessionId, prompt, viewColumn)this.sessionPanels: sessionId → panel). So the plumbing to boot a panel onto an existing session exists and is used; only the restore path declines to use it.

The other half is that nothing persists a session ID to begin with. In the webview bundle, state is written exactly once at startup, with a single key:

let api = acquireVsCodeApi();
let store = new StateStore(api);
store.update({ isFullEditor: window.IS_FULL_EDITOR });

So even a fixed deserializeWebviewPanel would have nothing to read. A complete fix needs both:

  1. webview — include the current session ID in the persisted state, and update it when the session ID is assigned or changes (e.g. on resume);
  2. extension — pass it through: setupPanel(panel, state?.sessionId, void 0, E).

Why the existing escape hatch doesn't cover this

claude-vscode.reopenClosedSession (Ctrl/Cmd+Shift+T) is gated on when: ... && claude-vscode.lastClosedWasSession. That context key only exists in a still-running window, so after a crash or restart the binding is inert. It addresses accidentally closing a tab, not restoring after the process dies — which is the case where recovery matters most.

Impact

No data is lost — transcripts are appended to ~/.claude/projects/<project>/*.jsonl during the turn and remain resumable. But recovery is entirely manual: the user must find the session in the sidebar list or run claude --resume, per tab, and must first realize the restored tab is empty rather than genuinely new. With several sessions open, a single crash silently detaches all of them at once.

Suggested fix

Persist the session ID alongside isFullEditor and pass it through in deserializeWebviewPanel. If full rehydration is undesirable as a default (cost of resuming N sessions on startup), a lighter option that would still remove the sharp edge: have the restored panel display the session it was attached to with an explicit "Resume" affordance, rather than presenting an empty panel indistinguishable from a new one — or gate auto-rehydration behind a setting, since none of the current 14 configuration options affect this.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗