Description
Wails v3 on Windows never registers WebView2's ProcessFailed event. When the WebView2 browser process dies — for any reason — the controller is left in a permanently invalid state: every subsequent COM call returns ERROR_INVALID_STATE (0x8007139F), the window renders blank, and only restarting the host app recovers. The app process itself stays alive, so the user is left staring at a dead white/blank window with no indication of what happened.
Concrete triggers:
Renderer-level failures (RENDER_PROCESS_EXITED / RENDER_PROCESS_UNRESPONSIVE) similarly leave a dead view where a simple re-navigation would recover.
Observable aftermath in a host log once the browser process is gone (every focus/resize event storms these):
[WebView2] Focus failed: The group or resource is not in the correct state to perform the requested operation.
[WebView2] SetSize failed: The group or resource is not in the correct state to perform the requested operation.
This is closely related to #5580's audit (transient COM errors exiting the process via errorCallback): alpha2.112 stopped the crash, but what remains is a window that can never recover. Handling ProcessFailed is the recovery half of that story.
Fix, validated
Branch: https://github.com/randalmurphal/wails/tree/fix/webview2-process-failed-recovery (single commit off the v3.0.0-alpha2.112 tag).
- Register
chromium.ProcessFailedCallback in setupChromium.
RENDER_PROCESS_EXITED / RENDER_PROCESS_UNRESPONSIVE → re-navigate to the last host-set URL (tracked in setURL; the dead webview can't be queried for it).
BROWSER_PROCESS_EXITED → rebuild: fresh edge.NewChromium(), re-run setupChromium, re-navigate. The old instance is abandoned rather than re-embedded — after a browser-process exit all its COM references dangle, and Embed's init-wait loop keys on a per-instance flag a used instance has already set, so re-embedding would return before a new controller exists.
- GPU/utility process failures are deliberately left alone: Chromium restarts those itself, and if it gives up, that arrives as
BROWSER_PROCESS_EXITED.
- Work is deferred out of the callback via
InvokeAsync, per WebView2 guidance about not calling controller methods reentrantly from event handlers.
Validated on Windows 11 26200 / WebView2 149.0.4022.98: with the browser process dying mid-session, the window rebuilds and re-renders in ~1–2s instead of staying blank.
Design points where you may want something different — happy to adjust in a PR:
- In-page state is lost on rebuild (it's gone regardless; the question is whether recovery should be automatic).
- Auto-reload on
RENDER_PROCESS_UNRESPONSIVE is opinionated — some apps may prefer waiting out a transient hang, so that case may want to be option-gated or surfaced as an event.
- There's currently no event surfaced to the app that a recovery happened; apps with meaningful frontend state may want a hook.
Happy to submit the branch as a PR if the approach looks right.
Environment
- Wails: v3.0.0-alpha2.112 (tagged)
- OS: Windows 11 Enterprise 25H2 (build 26200)
- WebView2 Runtime: 149.0.4022.98
Description
Wails v3 on Windows never registers WebView2's
ProcessFailedevent. When the WebView2 browser process dies — for any reason — the controller is left in a permanently invalid state: every subsequent COM call returnsERROR_INVALID_STATE (0x8007139F), the window renders blank, and only restarting the host app recovers. The app process itself stays alive, so the user is left staring at a dead white/blank window with no indication of what happened.Concrete triggers:
FATAL ... GPU process isn't usable. Goodbye.→ browser process exits).msedgewebview2.exefrom Task Manager (trivial repro of the same end state).Renderer-level failures (
RENDER_PROCESS_EXITED/RENDER_PROCESS_UNRESPONSIVE) similarly leave a dead view where a simple re-navigation would recover.Observable aftermath in a host log once the browser process is gone (every focus/resize event storms these):
This is closely related to #5580's audit (transient COM errors exiting the process via
errorCallback): alpha2.112 stopped the crash, but what remains is a window that can never recover. HandlingProcessFailedis the recovery half of that story.Fix, validated
Branch: https://github.com/randalmurphal/wails/tree/fix/webview2-process-failed-recovery (single commit off the v3.0.0-alpha2.112 tag).
chromium.ProcessFailedCallbackinsetupChromium.RENDER_PROCESS_EXITED/RENDER_PROCESS_UNRESPONSIVE→ re-navigate to the last host-set URL (tracked insetURL; the dead webview can't be queried for it).BROWSER_PROCESS_EXITED→ rebuild: freshedge.NewChromium(), re-runsetupChromium, re-navigate. The old instance is abandoned rather than re-embedded — after a browser-process exit all its COM references dangle, andEmbed's init-wait loop keys on a per-instance flag a used instance has already set, so re-embedding would return before a new controller exists.BROWSER_PROCESS_EXITED.InvokeAsync, per WebView2 guidance about not calling controller methods reentrantly from event handlers.Validated on Windows 11 26200 / WebView2 149.0.4022.98: with the browser process dying mid-session, the window rebuilds and re-renders in ~1–2s instead of staying blank.
Design points where you may want something different — happy to adjust in a PR:
RENDER_PROCESS_UNRESPONSIVEis opinionated — some apps may prefer waiting out a transient hang, so that case may want to be option-gated or surfaced as an event.Happy to submit the branch as a PR if the approach looks right.
Environment