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

  1. Retry the capture and instruct the user to pick a source with video (a screen/window, not an audio-only input).
  2. Confirm the app requested `{ video: true }` (it does) and that OS screen-recording permission covers video.
  3. Handle the ended-track case by re-prompting rather than throwing if the track state is 'ended'.
  4. 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

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


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