[BUG] Windows desktop: "Open in new window" is permanently dead for a session after its pop-out window closes abnormally — stale entries in session-popouts.json

Status Open
Reported on v2.1.246
Maintainer reply None cached
Activity 0 comments · opened Aug 28, 2026

Environment

| | |
|---|---|
| Claude desktop (MSIX / Microsoft Store) | 1.37937.3.0 |
| appVersion in main.log | 1.37937.3 |
| CCD | 2.1.246 |
| OS | Windows 11 Pro for Workstations, build 26200 |
| Node (Electron) | 24.18.1 |

Symptom

Open a session in its own window ("Open in new window"). If that window later disappears without a clean, user-initiated close — renderer crash, forced close, or an app restart that doesn't complete the teardown handshake — the action becomes a permanent silent no-op for that session only:

  • "Open in new window" on that session → nothing happens, no error, no log entry
  • The same session in the main window → works
  • The same session in split view → works
  • A brand-new session pops out fine

The broken state survives app restarts. The only remedy I found is deleting a state file, in a specific order.

Root cause

%APPDATA%\Claude\session-popouts.json is a registry of sessions the app believes are currently popped out into their own window. Entries are pruned only when the renderer reports its live pop-out list back to the main process — i.e. on a clean close. Any other way a pop-out window can disappear leaves its entry behind indefinitely.

Observed on my machine: the registry listed three sessions as popped out while zero pop-out windows existed.

// %APPDATA%\Claude\session-popouts.json  (titles/IDs redacted)
{"version":1,"popouts":[
  {"sessionId":"local_<uuid-1>","sessionType":"local","title":"<redacted>"},
  {"sessionId":"local_<uuid-2>","sessionType":"local","isSsh":false,"title":"<redacted>"},
  {"sessionId":"local_<uuid-3>","sessionType":"local","isSsh":false,"title":"<redacted>"}
]}

Actual visible top-level windows owned by Claude PIDs, via EnumWindows:

3868|True |Claude              <- main window, the only visible one
3868|False|DDE Server Window
3868|False|MSCTFIME UI
3868|False|Default IME
29376|False|Default IME
18468|False|Default IME

Worth flagging for anyone triaging: Get-Process -Name Claude | Select MainWindowTitle is not sufficient to check this — every Electron window shares one PID, so it reports a single title regardless of how many windows exist. You need EnumWindows.

The main process had been up ~22 hours at that point, accumulating stale entries across the day.

Inferred, not verified in code: "Open in new window" appears to be gated on this registry — when a sessionId is already listed, the app focuses a window it believes exists rather than creating one. This matches exactly which code paths keep working (main window and split view don't consult the registry) and which don't. I was able to confirm the main-process persistence layer from app.asar, but the renderer is fetched over the network, so I could not verify the gate itself.

Contributing factors in the main-process code

From the shipped app.asar bundle, all of these make the state harder to escape:

  1. The restore snapshot is single-shot. It is nulled on first read, so only one consumer can ever claim it.
  2. It expires after 600000 ms[popout-restore] Unclaimed snapshot expired, dropping.
  3. Secondary launches consume and discard it. main.log shows [popout-restore] Loaded 3 session popout(s) to restore immediately followed by Not main instance, returning early from app ready — four times in one day. So the natural user reflex (click the app icon to get the window back) reads the registry and throws it away without restoring anything.
  4. On quit, the app rewrites the file from its in-memory list. So deleting the file while the app is running has no effect. Any user who finds the file will almost certainly try exactly that, see it reappear, and conclude the file wasn't the problem.
  5. No user-facing escape hatch on Windows. The Ctrl/Cmd+R reload handler tests .meta, so it is macOS-only, and the only webContents.reload() menu entry I could find sits behind the dev menu. A renderer reload would very likely clear this, but Windows users have no way to trigger one.

Reproduction

  1. Open any session in a new window.
  2. Make that window go away abnormally — kill the renderer, force-close the app, or let a stealth update restart it.
  3. Relaunch. The pop-out does not come back.
  4. Try "Open in new window" on that session → silent no-op, permanently.
  5. Confirm %APPDATA%\Claude\session-popouts.json still lists it while no such window exists.

Workaround

Order matters, because of factor 4 above:

  1. Fully quit Claude — tray icon → Quit. Closing the window is not enough.
  2. Delete %APPDATA%\Claude\session-popouts.json.
  3. Relaunch.

Sessions themselves are never at risk; they live in %APPDATA%\Claude\claude-code-sessions\<install>\<org>\local_<id>.json. The pop-out file is purely window bookkeeping.

Suggested fixes

  1. Reconcile against reality. On startup, and when handling "Open in new window", check the registry against live windows. If no live window exists for a sessionId, drop the entry and create the window.
  2. Make the action self-healing. Focusing a window that no longer exists should fall back to creating one. It should never be a silent no-op — that gives the user no signal at all that anything is wrong.
  3. Prune on abnormal teardown too, not just on clean close — e.g. on render-process-gone / window closed regardless of origin.
  4. Expose a reload on Windows, or otherwise give users a supported way to resync renderer window state.

Related

  • #90172 — stealth restart silently destroying running sessions. This looks like a very plausible real-world trigger for the abnormal close that strands these entries.
  • #84748 — a different Windows pop-out defect (missing window controls), now closed.

View original on GitHub ↗