moeru-ai/airi · warning
initScreenCaptureForWindow should only be called once per wi
Error message
initScreenCaptureForWindow should only be called once per window
What it means
initScreenCaptureForWindow registers per-window IPC handlers (permissions, getSources, setSource/resetSource) keyed by the BrowserWindow object in an initializedWindows WeakSet. Calling it again with the same window logs this warning and returns; the previously created context and handlers stay active. It also throws outright if initScreenCaptureForMain has not run yet.
Source
Thrown at packages/electron-screen-capture/src/main/index.ts:197
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.
// REVIEW(@sumimakito): This has nothing to do with out side, probably related to Electron Bug, you can
// read more here https://github.com/electron/electron/issues/44504
const sources = await desktopCapturer.getSources(sourcesOptions)View on GitHub (pinned to 677329427f)
Solutions
- Register each window once at creation time, in one place (the window factory)
- Audit all initScreenCaptureForWindow call sites and consolidate them
- Remember the guard is keyed by window object: a reloaded (same) window is intentionally skipped, so do not add a second call to 'refresh' handlers
Example fix
// before
function createMainWindow() {
const win = new BrowserWindow({ ... })
initScreenCaptureForWindow(win)
win.webContents.on('did-finish-load', () => initScreenCaptureForWindow(win)) // duplicate
return win
}
// after
function createMainWindow() {
const win = new BrowserWindow({ ... })
initScreenCaptureForWindow(win)
return win
} Defensive patterns
Strategy: validation
Validate before calling
const initialized = new WeakSet<BrowserWindow>()
export function setupWindowCapture(win: BrowserWindow) {
if (initialized.has(win))
return
initScreenCaptureForWindow(win)
initialized.add(win)
} Prevention
- Call initScreenCaptureForWindow from exactly one place: the window factory
- Always call initScreenCaptureForMain first; the per-window call throws without it
- Remember the guard keys on the window object, so a reload of the same window is intentionally a no-op
When it happens
Trigger: Calling initScreenCaptureForWindow(window) twice for one BrowserWindow — e.g. calling it from both a window factory and a did-finish-load handler, or re-running setup code after an exception was already handled.
Common situations: Multiple modules each wiring screen capture for the same window; retry logic around window creation that accidentally re-invokes init; refactors that merged two call sites.
Related errors
- initScreenCaptureForMain must be called before calling initS
- timeout must be a positive finite number
- initScreenCaptureForMain should only be called once
- mutexAcquireTimeout must be a positive finite number
- Source with id ${request.sourceId} not found.
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/f1a0a6a351385f8c.
Report an issue: GitHub.