From eb89a72fa06ca24ecdb10ec969b9a7884cf4b5e9 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:37:15 -0700 Subject: [PATCH] fix: avoid renderer launch-failed reload loop (#4599) --- .../process-gone-classification.test.ts | 33 +++++++++++++++++++ .../process-gone-classification.ts | 6 ++++ 2 files changed, 39 insertions(+) diff --git a/src/main/crash-reporting/process-gone-classification.test.ts b/src/main/crash-reporting/process-gone-classification.test.ts index 4621d140b35..e143729fb29 100644 --- a/src/main/crash-reporting/process-gone-classification.test.ts +++ b/src/main/crash-reporting/process-gone-classification.test.ts @@ -250,6 +250,18 @@ describe('shouldRecordProcessGoneCrash', () => { ).toBe(true) }) + it('still records renderer launch failures for diagnostics', () => { + expect( + shouldRecordProcessGoneCrash({ + source: 'renderer', + processType: 'renderer', + reason: 'launch-failed', + exitCode: 18, + expectedTeardown: 'none' + }) + ).toBe(true) + }) + it('records non-SIGTERM killed process exits outside expected lifecycle teardown', () => { expect( shouldRecordProcessGoneCrash({ @@ -303,4 +315,25 @@ describe('shouldRecoverRendererAfterProcessGone', () => { }) ).toBe(false) }) + + it('does not recover renderer startup and security launch failures', () => { + expect( + shouldRecoverRendererAfterProcessGone({ + reason: 'launch-failed', + expectedTeardown: 'none' + }) + ).toBe(false) + expect( + shouldRecoverRendererAfterProcessGone({ + reason: 'launch-failed', + expectedTeardown: 'renderer-reload' + }) + ).toBe(false) + expect( + shouldRecoverRendererAfterProcessGone({ + reason: 'integrity-failure', + expectedTeardown: 'none' + }) + ).toBe(false) + }) }) diff --git a/src/main/crash-reporting/process-gone-classification.ts b/src/main/crash-reporting/process-gone-classification.ts index 1049eaca214..577f40e2ab9 100644 --- a/src/main/crash-reporting/process-gone-classification.ts +++ b/src/main/crash-reporting/process-gone-classification.ts @@ -8,6 +8,7 @@ const RECOVERABLE_UTILITY_SERVICE_NAMES = new Set([ 'network.mojom.NetworkService' ]) const RECOVERABLE_CHILD_PROCESS_REASONS = new Set(['abnormal-exit', 'crashed', 'killed']) +const NON_RECOVERABLE_RENDERER_REASONS = new Set(['integrity-failure', 'launch-failed']) function isWindowsControlTerminationExitCode(exitCode: number | null): boolean { if (exitCode === null) { @@ -91,5 +92,10 @@ export function shouldRecoverRendererAfterProcessGone({ if (expectedTeardown === 'app-shutdown') { return false } + // Why: these mean Chromium could not start or trust the renderer process; + // retrying the same BrowserWindow load can loop indefinitely on Windows. + if (NON_RECOVERABLE_RENDERER_REASONS.has(reason)) { + return false + } return !(reason === 'killed' && expectedTeardown === 'renderer-reload') }