moeru-ai/airi · error · Error
Selected source did not provide a live video track
Error message
Selected source did not provide a live video track
What it means
Thrown after getDisplayMedia resolves but the returned stream has no live video track (isActiveStream returned false). The user granted a stream, but it carries no video track — e.g. they shared audio-only, or the track ended immediately. The code stops the tracks then throws.
Source
Thrown at apps/stage-tamagotchi/src/renderer/composables/use-vision-screen-capture.ts:136
}
async function startStream() {
const sourceId = activeSourceId.value
if (!sourceId)
throw new Error('No active source selected')
if (isActiveStream(activeStream.value) && activeStreamSourceId.value === sourceId)
return activeStream.value!
clearActiveStream()
const stream = await selectWithSource(
() => sourceId,
async () => await navigator.mediaDevices.getDisplayMedia({ video: true, audio: false }),
)
if (!isActiveStream(stream)) {
stream.getTracks().forEach(track => track.stop())
throw new Error('Selected source did not provide a live video track')
}
activeStream.value = stream
activeStreamSourceId.value = sourceId
attachStreamLifecycle(stream, sourceId)
return stream
}
function stopStream() {
clearActiveStream()
}
function cleanup() {
stopStream()
revokeSourceObjectUrls(sources.value)
}
View on GitHub (pinned to 27111382b4)
Solutions
- Retry the capture and instruct the user to pick a source with video (a screen/window, not an audio-only input).
- Confirm the app requested `{ video: true }` (it does) and that OS screen-recording permission covers video.
- Handle the ended-track case by re-prompting rather than throwing if the track state is 'ended'.
- On macOS, verify Screen Recording permission in System Settings > Privacy & Security.
Defensive patterns
Strategy: validation
Validate before calling
function streamHasLiveVideoTrack(stream: MediaStream): boolean {
return stream.getVideoTracks().some(t => t.readyState === 'live' && t.enabled)
} Type guard
function isActiveStream(stream: MediaStream | null | undefined): stream is MediaStream {
return !!stream && stream.getVideoTracks().some(t => t.readyState === 'live')
} Try / catch
try {
await startStream()
} catch (e) {
if (e instanceof Error && e.message.includes('live video track')) {
// re-prompt the user to pick a source with video
} else throw e
} Prevention
- Verify OS screen-recording permission covers video before prompting.
- Filter source enumeration to video-capable sources only.
- Re-prompt on ended tracks rather than throwing hard.
When it happens
Trigger: User selected a source that exposes only audio; the video track was ended by the OS/source between grant and inspection; source (e.g. a closed window) became unavailable instantly; getDisplayMedia returned a stream whose video track is muted/ended.
Common situations: User picked an audio-only share target; the shared window was closed mid-handshake; permissions allow audio but not video; Electron/Chromium version quirk returning ended tracks.
Related errors
- No active source selected
- mutexAcquireTimeout must be a positive finite number
- initScreenCaptureForMain must be called before calling initS
- timeout must be a positive finite number
- Source with id ${request.sourceId} not found.
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/ef786be4296f9cc6.
Report an issue: GitHub.