From f2166e6bee21d2b57410d57e3034742494a002ae Mon Sep 17 00:00:00 2001 From: Santiago Espinosa Giraldo Date: Fri, 31 Jul 2026 15:45:30 -0500 Subject: [PATCH] fix(windows): prevent crash on activate after onboarding wizard closes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'closed' handlers that prune this.windows are wired once, in setupWindowEventHandlers(), over the windows that exist at startup (main, chat, llmResponse, settings). The onboarding wizard is created later in showOnboarding() and inserted into the same Map, so it never receives one — its entry outlives the destroyed BrowserWindow. The next 'activate' event then iterates the Map and calls isVisible() on the destroyed window: TypeError: Object has been destroyed at main.js:1552 at ApplicationController.onActivate (main.js:1551) Repro: launch with first-run onboarding, close the wizard, click the dock icon. - window.manager.js: attach a 'closed' handler when the onboarding window is created, so it is removed from the Map like the rest. - main.js: guard the onActivate iteration with isDestroyed(), matching the pattern already used throughout window.manager.js. --- main.js | 4 ++-- src/managers/window.manager.js | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/main.js b/main.js index 36ccf4b..c8d1410 100644 --- a/main.js +++ b/main.js @@ -1543,13 +1543,13 @@ class ApplicationController { } else if (this.isReady) { // When app is activated, ensure windows appear on current desktop const mainWindow = windowManager.getWindow("main"); - if (mainWindow && mainWindow.isVisible()) { + if (mainWindow && !mainWindow.isDestroyed() && mainWindow.isVisible()) { windowManager.showOnCurrentDesktop(mainWindow); } // Also handle other visible windows windowManager.windows.forEach((window, type) => { - if (window.isVisible()) { + if (!window.isDestroyed() && window.isVisible()) { windowManager.showOnCurrentDesktop(window); } }); diff --git a/src/managers/window.manager.js b/src/managers/window.manager.js index 52fa81b..22afac1 100644 --- a/src/managers/window.manager.js +++ b/src/managers/window.manager.js @@ -1365,6 +1365,16 @@ class WindowManager { onboardingWindow = await this.createWindow('onboarding'); this.windows.set('onboarding', onboardingWindow); + // The 'closed' handlers in setupWindowEventHandlers() are wired once, + // at startup, over the windows that exist then. The onboarding wizard + // is created later, so it needs its own handler — otherwise its entry + // outlives the BrowserWindow and later iterations over this.windows + // call methods on a destroyed object. + onboardingWindow.on('closed', () => { + logger.debug('Window closed', { type: 'onboarding' }); + this.windows.delete('onboarding'); + }); + // Once the wizard renderer signals it's ready, send it the // current first-run status so it can pre-populate correctly. onboardingWindow.webContents.once('did-finish-load', () => {