{"record":{"id":"73e7b1579acb120a","repo":"moeru-ai/airi","slug":"initscreencaptureformain-should-only-be-called-onc","errorCode":null,"errorMessage":"initScreenCaptureForMain should only be called once","messagePattern":"initScreenCaptureForMain should only be called once","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/electron-screen-capture/src/main/index.ts","lineNumber":117,"sourceCode":"  const {\n    forceCoreAudioTap = false,\n    mutexAcquireTimeout = 5000,\n  } = options\n\n  let log = useLogg('screen-capture').useGlobalConfig()\n  if (options?.loggerOptions?.logLevel) {\n    log = log.withLogLevelString((options?.loggerOptions?.logLevel ?? 'info') as LogLevelString)\n  }\n  if (options?.loggerOptions?.format) {\n    log = log.withFormat((options?.loggerOptions?.format ?? 'plain') as Format)\n  }\n\n  if (mutexAcquireTimeout <= 0 || !Number.isFinite(mutexAcquireTimeout) || Number.isNaN(mutexAcquireTimeout)) {\n    throw new Error('mutexAcquireTimeout must be a positive finite number')\n  }\n\n  if (initMainCalled) {\n    log.warn('initScreenCaptureForMain should only be called once')\n    return\n  }\n  initMainCalled = true\n  setSourceMutex = withTimeout(new Mutex(), mutexAcquireTimeout)\n\n  // Get other enabled features from the command line.\n  const otherEnabledFeatures = app.commandLine.getSwitchValue(featureSwitchKey)?.split(',')\n\n  // Remove the switch if it exists.\n  if (app.commandLine.hasSwitch(featureSwitchKey)) {\n    app.commandLine.removeSwitch(featureSwitchKey)\n  }\n\n  // Add the feature flags to the command line with any other user-enabled features concatenated.\n  const currentFeatureFlags = buildFeatureFlags({\n    otherEnabledFeatures,\n    forceCoreAudioTap,\n  })","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/electron-screen-capture/src/main/index.ts#L99-L135","documentation":"initScreenCaptureForMain is a one-time Electron main-process initializer: it validates options, sets the source mutex, and reads Chromium feature switches. A module-level initMainCalled flag makes a second call log this warning and return early, so any options passed to the second call are silently ignored.","triggerScenarios":"Calling initScreenCaptureForMain twice — e.g. from app bootstrap and again from window-creation code, in tests that init per test case, or after HMR re-runs a main-process bundle.","commonSituations":"Refactoring moves the init call and leaves the old one in place; tests importing the module multiple times without resetting module state; a plugin and the app both trying to own initialization.","solutions":["Call it exactly once from the main entry (e.g. inside app.whenReady()) and pass every option there","Remove the duplicate call site — search for all initScreenCaptureForMain references","In tests, reset module state between cases (vi.resetModules) or extract the init into a shared setup helper"],"exampleFix":"// before (two call sites)\nawait app.whenReady()\ninitScreenCaptureForMain({ loggerOptions: { logLevel: 'debug' } })\n// ... later, in another module\ninitScreenCaptureForMain({})\n\n// after (single call site, all options)\nawait app.whenReady()\ninitScreenCaptureForMain({ loggerOptions: { logLevel: 'debug' }, loopbackWithMute: true })","handlingStrategy":"validation","validationCode":"// single-flight guard in your own code\nlet screenCaptureMainInitialized = false\nexport async function ensureScreenCaptureMain() {\n  if (screenCaptureMainInitialized)\n    return\n  initScreenCaptureForMain({ loggerOptions: { logLevel: 'info' } })\n  screenCaptureMainInitialized = true\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Initialize main-process modules exactly once inside app.whenReady()","Wrap every cross-module initializer in a single ensureX() helper and call only that","In tests, reset module registry (vi.resetModules) between cases to re-arm one-time guards"],"tags":["electron","screen-capture","initialization","idempotency"],"backgroundTag":"duplicate-initialization","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}