moeru-ai/airi · error

initScreenCaptureForMain must be called before calling initS

Error message

initScreenCaptureForMain must be called before calling initScreenCaptureForWindow

What it means

Thrown by initScreenCaptureForWindow() when the module-level initMainCalled flag is still false, meaning initScreenCaptureForMain() has not run. The window initializer depends on the main-init step because it installs invoke handlers that reference the shared setSourceMutex created during main init.

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 27111382b4)

Solutions

  1. Call initScreenCaptureForMain() once during app.whenReady() before any window that uses screen capture is created.
  2. Ensure initScreenCaptureForMain did not throw or return early; check logs for the 'should only be called once' warning.
  3. If window init lives in a separate module/process, re-run main init there too (the flag is module-scoped).

Example fix

// before
app.whenReady().then(() => {
  const win = new BrowserWindow({ ... })
  initScreenCaptureForWindow(win)
})
// after
app.whenReady().then(() => {
  initScreenCaptureForMain()
  const win = new BrowserWindow({ ... })
  initScreenCaptureForWindow(win)
})
Defensive patterns

Strategy: validation

Validate before calling

let mainInitialized = false
function ensureMainInit() {
  if (!mainInitialized) {
    initScreenCaptureForMain()
    mainInitialized = true
  }
}

ensureMainInit()
initScreenCaptureForWindow(window)

Try / catch

try {
  initScreenCaptureForWindow(window)
} catch (error) {
  if (error instanceof Error && error.message.includes('before calling initScreenCaptureForWindow')) {
    initScreenCaptureForMain()
    initScreenCaptureForWindow(window)
  } else throw error
}

Prevention

When it happens

Trigger: Calling initScreenCaptureForWindow(window) in a BrowserWindow 'ready-to-show' or webContents hook without first having called initScreenCaptureForMain() during app initialization; main init threw earlier (e.g. bad mutexAcquireTimeout) so the flag stayed false; calling order swapped in a refactor.

Common situations: Adding screen capture to a new Electron entrypoint and forgetting the main init; initScreenCaptureForMain silently returned early due to a prior call but the window code is in a different process (utility process) where initMainCalled is per-module-instance; refactors that move init into a lazy path.

Related errors


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