transloadit/uppy · error · Error

Failed to get canvas context

Error message

Failed to get canvas context

What it means

captureScreenshot creates an offscreen canvas and throws when canvas.getContext('2d') returns null. Browsers return null for a 2d context when the canvas has zero or invalid dimensions — here video.videoWidth/videoHeight are 0 because the video element has no loaded metadata yet.

Source

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

      }

      const video = document.createElement('video')
      video.srcObject = stream

      await new Promise((resolve) => {
        video.onloadedmetadata = () => {
          video.play()
          resolve(null)
        }
      })

      const canvas = document.createElement('canvas')
      canvas.width = video.videoWidth
      canvas.height = video.videoHeight

      const ctx = canvas.getContext('2d')
      if (!ctx) {
        throw new Error('Failed to get canvas context')
      }

      ctx.drawImage(video, 0, 0, canvas.width, canvas.height)

      // Validate and set fallback for preferred image mime type
      let mimeType = this.opts.preferredImageMimeType
      if (!mimeType || !SUPPORTED_IMAGE_TYPES.includes(mimeType)) {
        this.uppy.log(
          `Unsupported image type "${mimeType}", falling back to image/png`,
          'warning',
        )
        mimeType = 'image/png'
      }

      const quality = 1

      return new Promise((resolve, reject) => {
        canvas.toBlob(

View on GitHub (pinned to 5d4dedd02a)

Solutions

  1. Retry the screenshot after a short delay or after the stream's video track is delivering frames (requestVideoFrameCallback)
  2. Ensure the video element is muted and play() is awaited before capture
  3. Verify the stream's track is live (track.readyState === 'live') before capturing

Example fix

// before
video.srcObject = stream
// immediately draw -> canvas.width = 0 -> ctx null

// after
video.srcObject = stream
await new Promise((r) => { video.onloadedmetadata = r })
await video.play()
if (video.videoWidth === 0) throw new Error('No frames yet')
Defensive patterns

Strategy: retry

Validate before calling

if (videoRef.videoWidth === 0 || videoRef.videoHeight === 0) {
  // wait for frames before allowing screenshot
}

Type guard

const hasVideoFrames = (v: HTMLVideoElement): boolean => v.readyState >= 2 && v.videoWidth > 0

Try / catch

try { await plugin.captureScreenshot() } catch (e) { if (e.message === 'Failed to get canvas context') setTimeout(() => plugin.captureScreenshot(), 500) }

Prevention

When it happens

Trigger: Calling captureScreenshot before the temporary video element fired loadedmetadata/loadeddata, so videoWidth/videoHeight are 0 and the context cannot be created (spec: getContext returns null if width/height are 0 in some engines, or the context is otherwise unavailable).

Common situations: Slow source warm-up, a stream with an ended/inactive video track, GPU/canvas context exhaustion, or browser quirks when the video was never played/muted to kick off decoding.

Related errors


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