moeru-ai/airi · error · Error
No screen source available
Error message
No screen source available
What it means
In the Tamagotchi (Electron) branch of the beat-sync detector (detector.ts:170), desktopCapturer sources of type 'screen' are listed and the first one is used to drive getDisplayMedia. If the callback receives an empty sources array, this error is thrown: Electron found zero screen-type capture sources, so there is no screen id to request.
Solutions
- On macOS, grant Screen Recording permission to the stage-tamagotchi/Electron app in System Settings and relaunch
- Widen sourcesOptions.types to include 'window' and pick from the combined list
- Detect this error and show an in-app prompt directing the user to OS privacy settings
Example fix
// before
{ sourcesOptions: { types: ['screen'] } }
// after
{ sourcesOptions: { types: ['screen', 'window'] } } Defensive patterns
Strategy: fallback
Validate before calling
const sources = await desktopCapturer.getSources({ types: ['screen', 'window'] })
if (sources.length === 0) {
// no capturable surface: OS permission or headless environment
showPermissionHint()
return
} Type guard
const hasScreenSources = (sources: { id: string }[]): boolean => sources.length > 0 Try / catch
try {
await startBeatSync({ env: StageEnvironment.Tamagotchi })
}
catch (error) {
if (error instanceof Error && error.message === 'No screen source available') {
promptForScreenRecordingPermission() // macOS System Settings hint
return
}
throw error
} Prevention
- Request/grant macOS Screen Recording permission before first capture
- Include 'window' in sourcesOptions.types so window-only setups still work
- Never assume a display source exists in CI or headless runs
When it happens
Trigger: macOS screen-recording permission denied to the Electron app, running on a headless/virtual display setup, or { types: ['screen'] } filtering out everything because only windows are reported.
Common situations: First run on macOS before Screen Recording permission is granted (sources come back empty), CI/headless machines, or systems where only window sources are enumerated.
Related errors
- checkMacOSScreenCapturePermission is only available on…
- requestMacOSScreenCapturePermission is only available on…
- Security-scoped Extension import access is not configured.
- Source with id not found.
- 1. Microphone permission not granted - browser should…
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/52dec31d13458690.
Report an issue: GitHub.
Appendix: 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 677329427f)