moeru-ai/airi · error · Error

No screen source available

Error message

No screen source available

What it means

Thrown by the beat-sync detector's Tamagotchi (Electron) path when `desktopCapturer` returns an empty source list, i.e. no screen sources were available to select. The selector callback receives `sources` and throws if its length is 0 before returning a source id, so the capture cannot proceed.

Source

Thrown at packages/stage-shared/src/beat-sync/detector.ts:170

        stopSource = () => {
          stream.getTracks().forEach(track => track.stop())
        }

        return node
      }
      case StageEnvironment.Tamagotchi: {
        if (!isElectronWindow(window)) {
          throw new Error(`Electron window is required for this environment: ${options.env}`)
        }

        // FIXME(Makito): Will refactor later
        const { createContext } = await import('@moeru/eventa/adapters/electron/renderer')
        const { selectWithSource } = setupElectronScreenCapture(createContext(window.electron.ipcRenderer).context)

        const stream = await selectWithSource(
          (sources: SerializableDesktopCapturerSource[]) => {
            if (sources.length === 0)
              throw new Error('No screen source available')
            return sources[0].id
          },
          async () => await navigator.mediaDevices.getDisplayMedia({
            video: true,
            audio: true,
          }),
          { sourcesOptions: { types: ['screen'] } },
        )

        const videoTracks = stream.getVideoTracks()

        videoTracks.forEach((track: MediaStreamTrack) => {
          track.stop()
          stream.removeTrack(track)
        })

        const node = ctx.createMediaStreamSource(stream)
        stopSource = () => {

View on GitHub (pinned to 27111382b4)

Solutions

  1. Grant Screen Recording permission to the Electron app in macOS System Settings (Privacy & Security), then restart the app.
  2. In headless/CI environments, provide a virtual display (xvfb) or skip beat-sync entirely.
  3. Catch the error and surface a user-facing message guiding the user to enable screen-capture permission.
  4. Confirm `types: ['screen']` matches available sources; broaden to include 'window' if appropriate for the use case.

Example fix

// before
const stream = await selectWithSource(sources => {
  if (sources.length === 0) throw new Error('No screen source available')
  return sources[0].id
}, ...)

// after
try {
  await startBeatSync()
} catch (e) {
  if (e.message === 'No screen source available') {
    showUser('Grant screen-recording permission to this app, then try again.')
  } else throw e
}
Defensive patterns

Strategy: try-catch

Validate before calling

import { desktopCapturer } from 'electron'

async function hasScreenSource(): Promise<boolean> {
  const sources = await desktopCapturer.getSources({ types: ['screen'] })
  return sources.length > 0
}

if (!await hasScreenSource()) {
  throw new Error('No screen source available. Grant screen-recording permission.')
}

Type guard

function hasScreenSources(sources: unknown[]): boolean {
  return Array.isArray(sources) && sources.length > 0
}

Try / catch

try {
  await startBeatSync()
} catch (e) {
  if (e instanceof Error && e.message === 'No screen source available') {
    showUser('Grant screen-recording permission to this app in System Settings, then restart.')
    return
  }
  throw e
}

Prevention

When it happens

Trigger: Running beat sync in the Electron (stage-tamagotchi) environment where `desktopCapturer.fetchSources({ types: ['screen'] })` yields no sources. This can happen when screen-recording permissions are denied, when running in a headless/sandboxed context with no displays, or when the OS blocks enumeration.

Common situations: macOS Screen Recording permission not granted to the Electron app; running in CI/headless without a virtual display; kiosk/lockdown policies that block screen enumeration; display sleep or no attached monitors.

Related errors


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