moeru-ai/airi · error · Error

mutexAcquireTimeout must be a positive finite number

Error message

mutexAcquireTimeout must be a positive finite number

What it means

initScreenCaptureForMain validates the mutexAcquireTimeout option (default 5000 ms) up front: it must be > 0, finite, and not NaN, because it is passed to withTimeout(new Mutex(), ...) to bound source-mutex acquisition. Any invalid custom value throws immediately during Electron main-process setup.

Solutions

  1. Pass a positive finite millisecond value, or omit the option to keep the 5000 ms default
  2. Sanitize env/config-derived numbers: Number.isFinite(t) && t > 0 before forwarding
  3. If you intended 'no timeout', keep a large finite value instead of Infinity — the API deliberately rejects it

Example fix

// before
initScreenCaptureForMain({ mutexAcquireTimeout: Number(process.env.SCREEN_CAP_TIMEOUT) }) // NaN when unset

// after
const t = Number(process.env.SCREEN_CAP_TIMEOUT)
initScreenCaptureForMain({ mutexAcquireTimeout: Number.isFinite(t) && t > 0 ? t : 5000 })
Defensive patterns

Strategy: validation

Validate before calling

const t = options.mutexAcquireTimeout ?? 5000
if (!(typeof t === 'number' && t > 0 && Number.isFinite(t)))
  throw new Error('mutexAcquireTimeout must be a positive finite number (ms)')
await initScreenCaptureForMain({ ...options, mutexAcquireTimeout: t })

Type guard

function isPositiveFinite(v: unknown): v is number {
  return typeof v === 'number' && v > 0 && Number.isFinite(v)
}

Prevention

When it happens

Trigger: Passing mutexAcquireTimeout: 0, a negative number, Infinity, or NaN — classically Number(undefinedEnvVar) or parseInt of an unset/blank config value.

Common situations: Timeout sourced from an environment variable or config file that is unset on another machine; a 'disable timeout' attempt passing 0; copy-pasted config with an empty string coerced to 0.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

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

let screenCaptureSourceMutexHandle: string | undefined
let setSourceMutexTimeoutHandle: NodeJS.Timeout | undefined

export function initScreenCaptureForMain(options: InitMainOptions = {}): void {
  const {
    forceCoreAudioTap = false,
    mutexAcquireTimeout = 5000,
  } = options

  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)
  }

  if (mutexAcquireTimeout <= 0 || !Number.isFinite(mutexAcquireTimeout) || Number.isNaN(mutexAcquireTimeout)) {
    throw new Error('mutexAcquireTimeout must be a positive finite number')
  }

  if (initMainCalled) {
    log.warn('initScreenCaptureForMain should only be called once')
    return
  }
  initMainCalled = true
  setSourceMutex = withTimeout(new Mutex(), mutexAcquireTimeout)

  // Get other enabled features from the command line.
  const otherEnabledFeatures = app.commandLine.getSwitchValue(featureSwitchKey)?.split(',')

  // Remove the switch if it exists.
  if (app.commandLine.hasSwitch(featureSwitchKey)) {
    app.commandLine.removeSwitch(featureSwitchKey)
  }

  // Add the feature flags to the command line with any other user-enabled features concatenated.

View on GitHub (pinned to 677329427f)