moeru-ai/airi · error · Error

initScreenCaptureForMain must be called before calling…

Error message

initScreenCaptureForMain must be called before calling initScreenCaptureForWindow

What it means

initScreenCaptureForWindow registers per-window IPC handlers and depends on state (source mutex, feature switches, shared context) that only initScreenCaptureForMain creates. It checks the initMainCalled flag and throws when window init runs first; the code comment marks this as unrecoverable rather than auto-recoverable.

Solutions

  1. Call initScreenCaptureForMain() first (after app is ready), then initScreenCaptureForWindow(win) for each window
  2. Centralize the ordering in one bootstrap function so windows are only initialized after main init completes
  3. If module state was reset (HMR/tests), re-run the main init before window init

Example fix

// before
app.whenReady().then(() => {
  initScreenCaptureForWindow(mainWindow) // Error: initScreenCaptureForMain must be called before calling initScreenCaptureForWindow
})

// after
app.whenReady().then(async () => {
  await initScreenCaptureForMain()
  initScreenCaptureForWindow(mainWindow)
})
Defensive patterns

Strategy: validation

Validate before calling

// Sequence explicitly in the bootstrap
app.whenReady().then(async () => {
  await initScreenCaptureForMain()
  for (const win of windows)
    initScreenCaptureForWindow(win)
})

Prevention

When it happens

Trigger: Calling initScreenCaptureForWindow(win) in the Electron main process before initScreenCaptureForMain() has run — e.g. window creation was moved ahead of the capture setup in the startup sequence, or a second entry point skips main init.

Common situations: Startup refactor reorders app.whenReady hooks; a feature module creates its window and initializes capture itself without the main init; tests constructing windows against a fresh module instance.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/67c02f7fd9b4acd3. Report an issue: GitHub.

Appendix: source

Thrown at packages/electron-screen-capture/src/main/index.ts:194

}

export function initScreenCaptureForWindow(window: BrowserWindow, options?: InitWindowOptions): void {
  let log = useLogg('screen-capture').useGlobalConfig()
  if (options?.loggerOptions?.logLevel) {
    log = log.withLogLevelString((options?.loggerOptions?.logLevel ?? 'info') as LogLevelString)
  }
  if (options?.loggerOptions?.format) {
    log = log.withFormat((options?.loggerOptions?.format ?? 'plain') as Format)
  }

  const windowId = window.id
  const windowTitle = tryWindowTitle(window)

  log.withFields({ windowId, windowTitle: tryWindowTitle(window, windowTitle) }).debug(`init for window`)

  if (!initMainCalled) {
    // Throwing an error because this is unlikely to be recoverable.
    throw new Error('initScreenCaptureForMain must be called before calling initScreenCaptureForWindow')
  }
  if (initializedWindows.has(window)) {
    log.withFields({ windowId, windowTitle: tryWindowTitle(window, windowTitle) }).warn('initScreenCaptureForWindow should only be called once per window')
    return
  }

  initializedWindows.add(window)

  const { context } = createContext(ipcMain, window, { onlySameWindow: true })
  const session = sessionModule.defaultSession

  defineInvokeHandler(context, screenCapture.checkMacOSPermission, async () => checkMacOSScreenCapturePermission())
  defineInvokeHandler(context, screenCapture.requestMacOSPermission, async () => requestMacOSScreenCapturePermission())

  defineInvokeHandler(context, screenCapture.getSources, async (sourcesOptions) => {
    // NOTICE(@nekomeowww): In probability of 9/10, the window thumbnail is purely empty or black, sources printed and
    // nothing is returned from the desktopCapturer API.
    // NOTICE(@sumimakito): Not only thumbnail is empty, the appIcon could be empty as well with nothing returned.

View on GitHub (pinned to 677329427f)