moeru-ai/airi · error · Error
No active source selected
Error message
No active source selected
What it means
Thrown by use-vision-screen-capture.startStream() when activeSourceId.value is empty. The composable requires a selected screen source before it can request a display-media stream; the guard fires before any getDisplayMedia call.
Source
Thrown at apps/stage-tamagotchi/src/renderer/composables/use-vision-screen-capture.ts:123
...source,
appIconURL: source.appIcon && source.appIcon.length > 0 ? createObjectUrlFromBytes(source.appIcon, 'image/png') : undefined,
thumbnailURL: source.thumbnail && source.thumbnail.length > 0 ? createObjectUrlFromBytes(source.thumbnail, 'image/jpeg') : undefined,
}))
const hasActiveSource = sources.value.some(source => source.id === activeSourceId.value)
const nextActiveSourceId = hasActiveSource ? activeSourceId.value : sources.value[0]?.id || ''
activeSourceId.value = nextActiveSourceId
}
finally {
isRefetching.value = false
hasFetchedOnce.value = true
}
}
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)View on GitHub (pinned to 27111382b4)
Solutions
- Ensure fetchSources() has completed and sources.value is non-empty before enabling the start button.
- Bind the source picker to activeSourceId and require a selection (or auto-select sources[0]) before startStream.
- Gate startStream behind `if (!activeSourceId.value) return` or show a 'select a source' prompt.
- Check that screen-capture permission was granted in the OS/browser.
Example fix
// before
async function startStream() {
const sourceId = activeSourceId.value
if (!sourceId) throw new Error('No active source selected')
}
// after
async function startStream() {
if (!activeSourceId.value && sources.value[0])
activeSourceId.value = sources.value[0].id
const sourceId = activeSourceId.value
if (!sourceId) throw new Error('No active source selected')
} Defensive patterns
Strategy: validation
Validate before calling
function canStartStream(): boolean {
return !!activeSourceId.value && sources.value.some(s => s.id === activeSourceId.value)
} Type guard
function hasActiveSource(id: string | undefined, sources: { id: string }[]): id is string {
return typeof id === 'string' && id.length > 0 && sources.some(s => s.id === id)
} Prevention
- Await fetchSources() and confirm sources.value.length > 0 before enabling start.
- Auto-select sources[0] when no source is chosen.
- Bind the source picker to activeSourceId so a selection is always present.
When it happens
Trigger: startStream() called before fetchSources() resolved, or after sources came back empty, or when the UI never bound a selection to activeSourceId. Also if the user's permission prompt during enumeration returned zero sources.
Common situations: Race: component calls startStream on mount before the async source enumeration completes; user revoked screen-capture permission so sources list is empty; refetch failed silently leaving activeSourceId unset.
Related errors
- Selected source did not provide a live video track
- 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/fb435d62e6872f11.
Report an issue: GitHub.