{"record":{"id":"4b9e1a29d05bda6e","repo":"responsively-org/responsively-app","slug":"mainwindow-is-not-defined","errorCode":null,"errorMessage":"\"mainWindow\" is not defined","messagePattern":"\"mainWindow\" is not defined","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"desktop-app/src/main/main.ts","lineNumber":203,"sourceCode":"      needsFocusFix = false;\n      triggeringProgrammaticBlur = true;\n      setTimeout(function () {\n        mainWindow!.blur();\n        mainWindow!.focus();\n        setTimeout(function () {\n          triggeringProgrammaticBlur = false;\n        }, 100);\n      }, 100);\n    }\n  });\n\n  mainWindow.on('ready-to-show', async () => {\n    if (!isAppInitiated) {\n      await initInstance();\n      setIsAppInitiated();\n\n      if (!mainWindow) {\n        throw new Error('\"mainWindow\" is not defined');\n      }\n      webPermissionHandlers.init();\n      if (process.env.START_MINIMIZED) {\n        mainWindow.minimize();\n      } else if (process.env.E2E_TEST === 'true' && process.env.E2E_HEADLESS === 'true') {\n        windowShownOnOpen = true;\n      } else if (process.env.E2E_TEST === 'true') {\n        mainWindow.showInactive();\n        windowShownOnOpen = true;\n      } else {\n        mainWindow.showInactive();\n        if (!windowShownOnOpen) {\n          windowShownOnOpen = true;\n          mainWindow.show();\n        } else {\n          mainWindow.showInactive();\n        }\n      }","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/responsively-org/responsively-app/blob/e5623c5a70c0c476b3f247c8d3980c7224e36410/desktop-app/src/main/main.ts#L185-L221","documentation":"This is an internal defensive assertion thrown inside the 'ready-to-show' event handler in createWindow. After the async initInstance() call completes, the module-level mainWindow variable is checked; if it became null/undefined (e.g. the window was closed during initialization), the code throws to prevent calling methods on a dead BrowserWindow reference. It signals a race between app initialization and window lifetime rather than a user-facing failure.","triggerScenarios":"The user (or the OS/test harness) closes the window while initInstance() is still awaiting during the 'ready-to-show' event, so the 'closed' handler sets mainWindow = null before the null check runs.","commonSituations":"Fast app quit on startup (user closes splash window immediately), E2E test harnesses tearing down the window mid-initialization, START_MINIMIZED flows combined with early quit, or any refactor that makes initInstance() async/slow.","solutions":["Guard the handler before awaiting: if (!mainWindow) return; at the top of the ready-to-show callback and after the await","Make the throw a graceful early return instead, since throwing inside an async Electron event handler only produces an unhandled rejection","Track window lifetime with a flag or use mainWindow.isDestroyed() rather than relying on the module-level variable","In tests, ensure the window stays open until ready-to-show completes"],"exampleFix":"// before\nawait initInstance();\nsetIsAppInitiated();\nif (!mainWindow) {\n  throw new Error('\"mainWindow\" is not defined');\n}\n// after\nif (!mainWindow || mainWindow.isDestroyed()) return;\nawait initInstance();\nif (!mainWindow || mainWindow.isDestroyed()) return;\nsetIsAppInitiated();","handlingStrategy":"type-guard","validationCode":"const win = mainWindow;\nif (!win || win.isDestroyed()) return; // run before AND after the await","typeGuard":"function isLiveWindow(w: Electron.BrowserWindow | null): w is Electron.BrowserWindow {\n  return w !== null && !w.isDestroyed();\n}","tryCatchPattern":"mainWindow.on('ready-to-show', async () => {\n  try {\n    await initInstance();\n  } catch (err) {\n    console.error('initInstance failed', err);\n    return;\n  }\n  if (!isLiveWindow(mainWindow)) return; // window closed during init\n  // ... proceed\n});","preventionTips":["Capture the window reference into a local const before any await","Check isDestroyed() after every await that touches webContents","Avoid throwing inside Electron async event handlers; prefer early return and logging","In E2E tests, keep the window alive until ready-to-show fires"],"tags":["electron","race-condition","null-reference","async"],"backgroundTag":"window-destroyed-during-async-init","analyzedSha":"e5623c5a70c0c476b3f247c8d3980c7224e36410","analyzedAt":"2026-08-31T10:58:12.271Z","schemaVersion":2},"datasetVersion":"2026-09-01T08:17:40.651Z"}