macOS: webview freezes after sleep (WebContent↔Networking IPC dies); no way to recycle the web process

Author: shimeCreated Sep 9, 2026Updated Sep 9, 2026

Symptom

After some sleep/wake cycles on macOS, a window's webview freezes for good: input is dead, no fetch the page issues ever resolves, nothing repaints. The native window, menus and the app's own server keep working. Focus, hide/unhide, minimize/restore and dock reopen do not recover it. Only a relaunch does.

What is actually broken

Instrumented on a frozen instance:

  • Page JS keeps running: our reconnect loop kept scheduling fetches (visible as scheduleLoad in the unified log), but none ever reached the server.
  • The app's com.apple.WebKit.Networking process still received bytes on the already-open socket to our server (nettop), so the socket and the server were fine. The bytes never reached the page.
  • ProcessThrottler transitions looked healthy, so this is not App Nap.
  • kill -9 of the app's com.apple.WebKit.WebContent process: WebKit respawned it in about a second, every page reloaded, full recovery, no app restart.

So the WebContent↔Networking IPC session is dead, and the only recovery is discarding the WebContent process and letting WebKit recreate it. A wake signal alone cannot fix it.

What electrobun offers today (checked on main, 19ce707)

  • No sleep/wake event: package/src/sdks/main/events/ApplicationEvents.ts has application-menu-clicked, context-menu-clicked, open-url, reopen, before-quit; nothing power-shaped. No NSWorkspace wake observer in package/src/native/macos/nativeWrapper.mm.
  • webViewWebContentProcessDidTerminate: is not implemented on MyNavigationDelegate, so an app never learns that its web process died.
  • No API to terminate or recycle a webview's web process. BrowserView.ts has none; the native SDKs' reloadWebview is a plain [WKWebView reload], which runs through the same dead process and does not recover it.

Proposal

  1. Electrobun.events.on("did-wake", ...): an NSWorkspaceDidWakeNotification observer in nativeWrapper.mm, forwarded the way reopen already is via g_appReopenHandler.
  2. webview.terminateWebProcess(), plus a real webViewWebContentProcessDidTerminate: that emits a webview event (optionally auto-reloading). Together they let an app recover in place without hunting WebKit-owned pids from outside electrobun.

Workaround we ship

The page heartbeats POST /alive every 5s. If windows are open and no window has beaten for 20s after a wake, the main process finds the com.apple.WebKit.Networking peer on our server port (lsof), resolves its responsible pid via the unprivileged responsibility_get_pid_responsible_for_pid (launchctl procinfo is root-gated on macOS 26.5), and kill -9s every com.apple.WebKit.WebContent sharing it. WebKit respawns and reloads. It works, but no app should have to do this.

Versions

Observed on electrobun 1.16.0, macOS 26.5.1, Apple Silicon. Gaps above verified against main at 19ce707 (v2.0.2-beta.17).


Written by Claude Fable on behalf of @shime while building https://dialog.software.