Skip to content

fix: guard webview find against disposed frame subtree (fixes #339314) - #339331

Merged
Dmitriy Vasyura (dmitrivMS) merged 6 commits into
microsoft:mainfrom
vscodebot-pr:fix/webview-find-disposed-frame-339314-aw-37028364563
Oct 12, 2026
Merged

Dmitriy Vasyura (dmitrivMS) merged 6 commits into
microsoft:mainfrom
vscodebot-pr:fix/webview-find-disposed-frame-339314-aw-37028364563

Conversation

@vscodebot-pr

Copy link
Copy Markdown
Contributor

Summary

WebviewMainService.getFrameByName (electron-main) reads getWebContents(id).mainFrame.framesInSubtree.find(...) unconditionally. When a find / stop-find IPC request is handled against a webContents whose render frame has already been torn down (window closed, navigated away, or detached editor window disposed), mainFrame.framesInSubtree is undefined, so .find(...) throws TypeError: Cannot read properties of undefined (reading 'find') in the main process. This new-in-1.140.0 bucket affects 566 users / 736 hits across Mac, Windows, and Linux.

Fixes #339314
Recommended reviewer: @dmitrivMS

Culprit Commit

Field Value
Commit 9cc2a44b
Author @dmitrivMS
PR #337403
Message webview: Fix find in detached editor windows (#337403)
Why The commit reworked getFrameByName to resolve the frame via the shared getWebContents(id) helper and routes stop-find/find requests through auxiliary web-contents IDs (detached editor windows) as well as main window IDs. This widened the set of webContents the find path runs against — including auxiliary/detached contents that can be disposed between request and handling — so mainFrame.framesInSubtree can now be undefined at the dereference, which the prior window-only path did not expose. Verified ancestor of shipped commit 07f806f9 (first appears in 1.140.0~389, matching the "new in 1.140.0" anomaly).

Code Flow

sequenceDiagram
    participant Renderer as Webview (renderer)
    participant IPC as ipcMain / ChannelServer
    participant Service as WebviewMainService
    participant Electron as Electron WebContents

    Renderer->>IPC: stopFindInFrame(id, frameName)
    IPC->>Service: call stopFindInFrame
    Service->>Service: getFrameByName(id, frameName)
    Note over Electron: ⚠️ Root cause:<br/>render frame already disposed,<br/>framesInSubtree is undefined
    Service->>Electron: getWebContents(id).mainFrame.framesInSubtree
    Note over Service: 💥 TypeError: Cannot read<br/>properties of undefined (reading 'find')
Loading

Affected Files

File Role Evidence
src/vs/platform/webview/electron-main/webviewMainService.ts crash site & fix L96 (from stack): getWebContents(id).mainFrame.framesInSubtree.find(...) dereferences undefined when the webContents' render frame is disposed

Repro Steps

The error is a timing-dependent race on the main process; it fires when a stop-find/find reply is handled after the target render frame is gone:

  1. Open a webview-backed editor (e.g. Markdown preview, Simple Browser, or a detached editor window) and start Find (Cmd/Ctrl+F) inside it.
  2. Close the webview / window (or navigate it away) while a find or stop-find request is in flight.
  3. The in-flight stopFindInFrame / findInFrame IPC call reaches getFrameByName, whose webContents.mainFrame.framesInSubtree is now undefined, throwing the TypeError.

How the Fix Works

Chosen approach — webviewMainService.ts → getFrameByName(): the producer of the invalid state is Electron's render-frame disposal, which lives outside microsoft/vscode and cannot be reordered or awaited, so a consumer-side guard at this external boundary is the correct fix. getFrameByName now returns WebFrameMain | undefined: it checks contents.isDestroyed() and contents.mainFrame?.framesInSubtree before calling .find(...), returning undefined when the frame subtree is gone. The two callers (findInFrame, stopFindInFrame) already treat a missing frame as a no-op, so they early-return on undefined. This mirrors the existing disposed-frame guards already in this codebase: the contents.isDestroyed() check in setIgnoreMenuShortcuts (same file) and the frame.isDestroyed() guard in app.ts's isSafeFrame.

The genuine Unknown frame throw is deliberately preserved for the live-frame case (a real frame subtree that does not contain the named frame), so the error-telemetry pipeline still surfaces that distinct, actionable condition — only the disposed-webContents undefined read is suppressed.

Alternatives considered: adding ?./try/catch directly at the crash-site .find(...) was rejected because it would also swallow the meaningful Unknown frame signal and does not express why the value is absent; guarding explicitly on isDestroyed() / missing subtree keeps the disposed-frame no-op distinct from the live-frame "frame not found" error.

Recommended Owner

@dmitrivMS — author of the culprit commit #337403 and an active microsoft/vscode team member (238 commits in the last 90 days), who owns the webview find-in-frame routing changed by that PR.

…ft#339314)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The focused lifecycle guard fixes the reported crash while preserving live-frame error handling.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
What changed in this PR

Prevents main-process crashes when webview find requests arrive after frame disposal.

Changes:

  • Returns early when web contents or its frame subtree is unavailable.
  • Preserves errors for unknown frames in live subtrees.
File Description
src/​vs/​platform/​webview/​electron-main/​webviewMainService.ts Guards find operations against disposed frame trees.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Updated comment to clarify frame subtree availability after disposal.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Handle unavailable hosts and frames without unhandled find errors. Avoid idle stop requests while preserving retained-selection clearing, and add regression coverage for microsoft#339314.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The live-frame error contract contradicts the PR description, and the auxiliary web-contents regression path lacks direct coverage.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dmitrivMS
Dmitriy Vasyura (dmitrivMS) merged commit 0185f13 into microsoft:main Oct 12, 2026
35 checks passed
@vs-code-engineering vs-code-engineering Bot added this to the 1.143.0 milestone Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Error] unhandlederror-Cannot read properties of undefined (reading 'find')

5 participants