transloadit/uppy · error · Error

No video stream available

Error message

No video stream available

What it means

Thrown by ScreenCapture's startRecording when selectVideoStreamSource() resolves to false, meaning no screen/window/tab stream was obtained before recording started. This happens when getDisplayMedia is unsupported or the stream selection returned false, so there is nothing to record.

Source

Thrown at packages/@uppy/screen-capture/src/ScreenCapture.tsx:298

      .catch((err) => {
        if (err.name === 'NotAllowedError') {
          this.uppy.info(this.i18n('micDisabled'), 'error', 5000)
          this.uppy.log(this.i18n('micDisabled'), 'warning')
        }
        return false
      })
  }

  startRecording(): void {
    const options: { mimeType?: string } = {}
    this.capturedMediaFile = null
    this.recordingChunks = []
    const { preferredVideoMimeType } = this.opts

    this.selectVideoStreamSource()
      .then((videoStream) => {
        if (videoStream === false) {
          throw new Error('No video stream available')
        }
        // Attempt to use the passed preferredVideoMimeType (if any) during recording.
        // If the browser doesn't support it, we'll fall back to the browser default instead
        if (
          preferredVideoMimeType &&
          MediaRecorder.isTypeSupported(preferredVideoMimeType) &&
          getFileTypeExtension(preferredVideoMimeType)
        ) {
          options.mimeType = preferredVideoMimeType
        }

        // prepare tracks
        const tracks = [videoStream.getVideoTracks()[0]]

        // merge audio if exits
        if (this.audioStream) {
          tracks.push(this.audioStream.getAudioTracks()[0])
        }

View on GitHub (pinned to 5d4dedd02a)

Solutions

  1. Check navigator.mediaDevices?.getDisplayMedia is available and the page is served over HTTPS before enabling the ScreenCapture plugin
  2. Only trigger recording from the plugin's own UI state (RECORDING/PAUSED states), not programmatically before a stream exists
  3. In tests/headless environments, stub getDisplayMedia or skip the plugin

Example fix

// before
const btn = plugin.getRecordButtonProps()
btn.onClick() // may throw: no stream yet

// after
if (navigator.mediaDevices?.getDisplayMedia && plugin.getPluginState().screenRecActive !== undefined) {
  plugin.getRecordButtonProps().onClick()
}
Defensive patterns

Strategy: validation

Validate before calling

const canRecord = typeof navigator.mediaDevices?.getDisplayMedia === 'function'
if (canRecord) uppy.use(ScreenCapture)

Type guard

const supportsScreenCapture = (): boolean =>
  typeof navigator !== 'undefined' &&
  typeof navigator.mediaDevices?.getDisplayMedia === 'function'

Try / catch

try { plugin.getRecordButtonProps().onClick() } catch (e) { if (e.message === 'No video stream available') uppy.info('Screen sharing unavailable', 'error', 5000) }

Prevention

When it happens

Trigger: Calling startRecording (via getRecordButtonProps().onClick) in a browser without navigator.mediaDevices.getDisplayMedia, or when the internal selectVideoStreamSource promise resolves false (e.g. plugin not mounted, stream already stopped, or inactive video track).

Common situations: Running in a non-secure context (http, not localhost), unsupported browser (Safari/Firefox without screen capture), running in a headless test environment, or starting recording after the user cancelled the screen picker.

Related errors


AI-assisted analysis of transloadit/uppy@5d4dedd02a (2026-08-28). Data as JSON: /api/errors/34fb3df84f83e785. Report an issue: GitHub.