Describe the bug
When a restored tab has no usable content (rawContent is undefined), switching to it does not swap the Monaco buffer — the editor keeps displaying the previous tab's content under the new tab's title. The next content-change event then writes that stale buffer into the wrong tab's store, and with auto-save enabled the wrong content is written to the wrong file on disk. This is silent data corruption.
How we hit it
We hit this in a version-mix scenario while working on #211: a v2.6.11 build restored a session snapshot written in the newer window-state-only format proposed there (which intentionally carries no rawContent). restoreState assigns the parsed tabs wholesale:
restoreState(jsonBuffer) {
const data = JSON.parse(jsonBuffer);
if (data && Array.isArray(data.tabs)) {
this.tabs = data.tabs; // ← shape never validated
...
so every restored tab had rawContent === undefined. Observed live (screenshot-verified): a window with tabs 3.md (disk content 3333) and 4.md (disk content 4444) displayed 4444 under the 3.md tab after a tab switch. One edit event + auto-save later, 3.md on disk becomes 4444 — we saw exactly that in an earlier uninstrumented run ("both files ended up with the same content").
Why it happens
restoreState trusts the snapshot's shape blindly — no field validation, no version check (the editor never wrote a version field historically).
- The editor's tab-switch sync has no guard for non-string content: with
content undefined the setValue swap is skipped/throws, leaving the stale buffer visible under the new tab.
- The
onDidChangeModelContent handler attributes whatever the editor holds to tabManager.activeTabId at event time, so a stale buffer + any change event = misattributed content.
Expected behavior
A tab with missing/invalid restored content should display as empty (or reload from its path), never as another tab's content — and nothing should be auto-saved from a buffer that was never attributed to that tab by the user.
Suggested hardening (all cheap)
- Normalize in
restoreState: default rawContent/originalContent to '', drop entries without the expected fields; ignore snapshots whose version is newer than the build understands.
- Guard the editor sync: treat non-string tab content as
'' before setValue.
Note: #211 side-steps the cross-version trigger by moving the new snapshot format to its own storage key (an older build simply finds nothing to restore after a downgrade), but the editor-side robustness gap is independent of that PR and worth fixing for any malformed snapshot.
Device
- OS: macOS (Darwin 25.x)
- App Version: v2.6.11
🤖 Generated with Claude Code
Describe the bug
When a restored tab has no usable content (
rawContentisundefined), switching to it does not swap the Monaco buffer — the editor keeps displaying the previous tab's content under the new tab's title. The next content-change event then writes that stale buffer into the wrong tab's store, and with auto-save enabled the wrong content is written to the wrong file on disk. This is silent data corruption.How we hit it
We hit this in a version-mix scenario while working on #211: a v2.6.11 build restored a session snapshot written in the newer window-state-only format proposed there (which intentionally carries no
rawContent).restoreStateassigns the parsed tabs wholesale:so every restored tab had
rawContent === undefined. Observed live (screenshot-verified): a window with tabs3.md(disk content3333) and4.md(disk content4444) displayed4444under the3.mdtab after a tab switch. One edit event + auto-save later,3.mdon disk becomes4444— we saw exactly that in an earlier uninstrumented run ("both files ended up with the same content").Why it happens
restoreStatetrusts the snapshot's shape blindly — no field validation, no version check (the editor never wrote a version field historically).contentundefined thesetValueswap is skipped/throws, leaving the stale buffer visible under the new tab.onDidChangeModelContenthandler attributes whatever the editor holds totabManager.activeTabIdat event time, so a stale buffer + any change event = misattributed content.Expected behavior
A tab with missing/invalid restored content should display as empty (or reload from its
path), never as another tab's content — and nothing should be auto-saved from a buffer that was never attributed to that tab by the user.Suggested hardening (all cheap)
restoreState: defaultrawContent/originalContentto'', drop entries without the expected fields; ignore snapshots whoseversionis newer than the build understands.''beforesetValue.Note: #211 side-steps the cross-version trigger by moving the new snapshot format to its own storage key (an older build simply finds nothing to restore after a downgrade), but the editor-side robustness gap is independent of that PR and worth fixing for any malformed snapshot.
Device
🤖 Generated with Claude Code