moeru-ai/airi · error · Error
Failed to create canvas context
Error message
Failed to create canvas context
What it means
Thrown by the frame-capture helper when canvas.getContext('2d') returns null. The canvas was created and sized from the video dimensions, but the browser refused to hand back a 2D rendering context. This is rare — getContext('2d') returns null only under severe resource exhaustion or a corrupted canvas state.
Source
Thrown at apps/stage-tamagotchi/src/renderer/composables/use-vision-screen-capture.ts:171
}
function captureFrame(video: HTMLVideoElement, quality = 0.82, maxWidth = 1280, maxHeight = 720) {
if (!video || video.readyState < 2)
return null
const canvas = document.createElement('canvas')
const sourceWidth = video.videoWidth
const sourceHeight = video.videoHeight
if (sourceWidth <= 0 || sourceHeight <= 0)
return null
const scale = Math.min(maxWidth / sourceWidth, maxHeight / sourceHeight, 1)
canvas.width = Math.round(sourceWidth * scale)
canvas.height = Math.round(sourceHeight * scale)
const ctx = canvas.getContext('2d')
if (!ctx)
throw new Error('Failed to create canvas context')
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
return canvas.toDataURL('image/jpeg', quality)
}
return {
sources,
activeSourceId,
activeSource,
activeStream,
isRefetching,
hasFetchedOnce,
refetchSources,
startStream,
stopStream,
cleanup,
captureFrame,
}View on GitHub (pinned to 27111382b4)
Solutions
- Reduce concurrent capture canvases and reuse a single canvas where possible.
- Free canvas references (set width/height to 0) after capture to release GPU memory.
- Catch the null context and skip the frame instead of throwing, so the stream keeps running.
- If persistent, check for GPU/process memory pressure in Electron's task manager.
Example fix
// before
const ctx = canvas.getContext('2d')
if (!ctx)
throw new Error('Failed to create canvas context')
// after
const ctx = canvas.getContext('2d')
if (!ctx)
return null
ctx.drawImage(video, 0, 0, canvas.width, canvas.height) Defensive patterns
Strategy: fallback
Validate before calling
function canAcquire2dContext(): boolean {
const probe = document.createElement('canvas')
probe.width = 1; probe.height = 1
return probe.getContext('2d') !== null
} Type guard
function has2dContext(canvas: HTMLCanvasElement): canvas is HTMLCanvasElement & { getContext(c: '2d'): CanvasRenderingContext2D } {
return canvas.getContext('2d') !== null
} Prevention
- Reuse a single canvas across frames instead of allocating per capture.
- Set canvas width/height to 0 when done to release GPU memory.
- Return null (skip frame) instead of throwing when context acquisition fails.
When it happens
Trigger: GPU/context pool exhausted after many simultaneous canvases; the renderer process hit a hard memory ceiling; canvas was tainted or created during teardown; Chromium bug under headless/constrained GPU.
Common situations: Long-running capture sessions leaking canvases; very high frame-rate capture thrashing the GPU; running under a software-rendered/headless GPU; tab/process near OOM.
Related errors
- Generation failed
- No active source selected
- Selected source did not provide a live video track
- mutexAcquireTimeout must be a positive finite number
- initScreenCaptureForMain must be called before calling initS
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/7f8baea3f64a5e09.
Report an issue: GitHub.