Repository navigation
[Bug]: Desktop main process segfaults when a preview tab's renderer dies during an agent snapshot screenshot #24026
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/desktop
Steps to reproduce
Seen once in normal use. These steps follow the crash's timeline:
- Have an agent drive a desktop preview tab (
preview_open, thenpreview_wait_for/preview_snapshot/preview_evaluate) on a page whose renderer becomes busy. Here it was a local React 19.2 dev build whose memory grew to about 2 GB. - The tab stops answering:
waitFor,snapshot,evaluateandnavigateall time out (PreviewAutomationTimeoutError). - The tab's renderer later dies (here: out of memory).
- The desktop main process crashes immediately (SIGSEGV at 0x0).
A likely deterministic repro, which I have not verified: start preview_snapshot on a tab whose renderer is stalled, then kill that renderer process while the CDP Page.captureScreenshot is still pending.
Expected behavior
The preview tab reports its crashed renderer and the app keeps running.
Actual behavior
The Electron browser process dies with EXC_BAD_ACCESS (SIGSEGV) KERN_INVALID_ADDRESS at 0x0 on CrBrowserMain, which takes down the bundled server too. The crashed renderer itself aborted out of memory 0–1 s earlier (same capture time).
Symbolicated with Electron's official v44.4.5 darwin-arm64 dSYM (Electron Framework UUID 4C4C44ED-5555-3144-A1CB-427AA45E6F33 matches the crash report):
Thread 0 Crashed:: CrBrowserMain
content::RenderWidgetHostImpl::OnSnapshotFromSurfaceReceived(int, int, base::expected<viz::CopyOutputBitmapWithMetadata, content::CopyFromSurfaceError> const&) render_widget_host_impl.cc:3916
content::RenderWidgetHostViewChildFrame::CopyFromSurface(...)::$_0 render_widget_host_view_child_frame.cc:1020 ← <webview> guest
base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork()
base::MessagePumpCFRunLoopBase::RunWorkSource(void*)
...
content::BrowserMainLoop::RunMainMessageLoop()
Crashed preview renderer, same moment:
CrRendererMain EXC_BREAKPOINT
partition_alloc::internal::OnNoMemoryInternal(unsigned long)
blink::Partitions::HandleOutOfMemory(unsigned long)
...
blink::SerializedScriptValue::Create()
blink::PerformanceMeasure::Create(...)
blink::Performance::MeasureWithDetail(...)
v8_inspector::TaskInfo::runTask(...) ← React dev "Performance Tracks"
blink::MessagePort::DispatchMessageEvent(...)
Impact
Blocks work completely (the whole app and every thread go down)
Version or commit
0.0.46-nightly.20261011.2994 (Electron 44.4.5 / Chrome 152.0.7977.130). The code path is unchanged on main @ d7a8d6f (Electron 44.9.3).
Environment
macOS 15.7.5 (24G624), Apple Silicon. Claude Code provider driving desktop preview tabs over the preview MCP tools.
Root cause (upstream Chromium)
OnSnapshotFromSurfaceReceived is the callback for RenderWidgetHostImpl::GetSnapshotFromBrowser(..., from_surface=true), which DevTools uses for Page.captureScreenshot. When a copy fails, Chrome ≤156 retries with GetView()->CopyFromSurface(...) and never null-checks GetView(). Once the renderer is gone, the view is null, and the retry dereferences it.
Fixed upstream in Chromium f49f3e5, "Fix null ptr deref crash in Page.captureScreenshot when renderer gone" (crbug.com/567321049, CL 8485185, first in 157.0.8083.0). It adds && GetView() to the retry condition. No stable Electron has it: 44-x-y is on Chromium 152 and 45-x-y on 156. Only Electron main and the 46 nightlies (158) include it.
Why T3 hits it
Desktop preview snapshots send Page.captureScreenshot to the guest through the CDP relay (ServerBrowserPage.captureViewport → DesktopBrowserHost → sendPageCommand → debugger.sendCommand). A CDP command can't be cancelled. When the snapshot deadline passes on a stalled tab, the capture stays pending in Chromium, and each retried snapshot can leave another one behind. Any capture still pending when the renderer dies crashes the app.
Electron's own webContents.capturePage() isn't affected. It null-checks the view and never retries through GetView(). It does behave differently on hidden or cold guests, which is why #19931 and #19913 handle those cases carefully.
Possible directions (for maintainers to choose)
- Answer
Page.captureScreenshotinsendPageCommandwithcapturePage()until Electron ships Chromium ≥157. This removes the crash path but has to preserve the scale, zoom, scroll and hidden-tab behavior from fix(server): desktop-drawn preview snapshots match the page's scale and viewport #19913 and fix(desktop): capture fresh pixels from background previews #19931. It is a larger, riskier change, temporary until the Electron bump. - Allow only one pending CDP screenshot per tab, and don't start another while an earlier one is still unresolved. This narrows the window but doesn't eliminate it. It is small (a per-tab pending counter in the relay plus one focused test) and doesn't change how screenshots are taken. I'm happy to send a PR for this once the direction is agreed.
- Request an Electron backport of
f49f3e5to 44-x-y and 45-x-y. Electron's patch is a one-line cherry-pick; there's a precedent in fix: cherry-pick 431b8be6a111 from chromium electron/electron#54912.
Logs
Timeline from ~/.t3/userdata/logs (server and desktop traces), local time:
09:50:27 preview_open http://localhost:5173/chat → guest renderer created
09:50:59 PreviewAutomationTimeoutError: waitFor timed out after 60000ms
09:52:01 PreviewAutomationTimeoutError: waitFor timed out after 60000ms
09:53:07 PreviewAutomationTimeoutError: snapshot timed out after 15000ms
09:53:25 PreviewAutomationTimeoutError: evaluate timed out after 15000ms
09:53:47 PreviewAutomationTimeoutError: navigate timed out after 15000ms
09:54:06 preview_open (second tab) → its renderer grows 243 MB → 2.1 GB by 10:03
10:05:17.034 PreviewManager.close
10:05:17.27 main process SIGSEGV (above); preview renderer OOM abort at the same capture time
Related but different crashes: #8332 and #9067 (debugger use-after-free, fixed in #9068), and #20395 (relay JSON.stringify OOM, open PR #23461). #21980 covers crashed-tab recovery.
Workaround
Avoid agent snapshots on preview tabs that have stopped responding; close them instead. Keep heavy dev-mode pages out of long agent preview sessions.
Activity
fix(desktop): drop screenshots a released preview relay left queued
test(desktop): wait on replies instead of a macrotask in screenshot q…