{"record":{"id":"7789eafb34a7b824","repo":"hcengineering/platform","slug":"canvasstreamcomposer-unable-to-get-canvas-context","errorCode":null,"errorMessage":"CanvasStreamComposer: unable to get canvas context","messagePattern":"CanvasStreamComposer: unable to get canvas context","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/recorder-resources/src/composer.ts","lineNumber":273,"sourceCode":"    case 'medium':\n      return 0.15\n    case 'large':\n      return 0.2\n    default:\n      return 0.15\n  }\n}\n\nfunction createCanvasElement (): { canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D } {\n  const canvas = document.createElement('canvas')\n\n  const ctx = canvas.getContext('2d', {\n    alpha: false,\n    desynchronized: true\n  })\n\n  if (ctx === null) {\n    throw new Error('CanvasStreamComposer: unable to get canvas context')\n  }\n\n  ctx.imageSmoothingEnabled = true\n  ctx.imageSmoothingQuality = 'high'\n\n  return { canvas, ctx }\n}\n\nfunction createVideoElement (): HTMLVideoElement {\n  const element = document.createElement('video')\n  element.autoplay = true\n  element.playsInline = true\n  return element\n}\n\nfunction updateCameraPos (\n  cameraSize: CameraSize,\n  cameraPos: CameraPosition,","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/plugins/recorder-resources/src/composer.ts#L255-L291","documentation":"createCanvasElement requests a 2D rendering context from a freshly created <canvas> with { alpha: false, desynchronized: true }. When canvas.getContext('2d') returns null — meaning the browser could not create a drawing surface — the recorder's CanvasStreamComposer throws this error because it cannot composite video frames without a 2D context.","triggerScenarios":"Creating the recorder composer in an environment where getContext('2d') returns null: hardware acceleration disabled/unavailable, GPU process crash, browser with canvas support disabled by policy, memory exhaustion preventing backing-buffer allocation, or a non-DOM environment (SSR/headless without canvas).","commonSituations":"Corporate browsers with 'Disable canvas' / hardware-acceleration-off policies; Linux headless environments lacking GPU drivers; low-memory devices; Electron/webview builds with experimental canvas features disabled; huge requested canvas dimensions exceeding the browser's max canvas area.","solutions":["Enable hardware acceleration in the browser (chrome://settings → 'Use hardware acceleration when available') and restart.","Check browser/enterprise policy does not block canvas APIs (e.g. DisableWebGL/CanvasReadback policies).","Reduce the requested canvas dimensions in the composer to stay within the browser's canvas size limits.","Guard the call site: test document.createElement('canvas').getContext('2d') before constructing the composer and surface a graceful fallback (e.g. audio-only recording)."],"exampleFix":"// before\nconst { canvas, ctx } = createCanvasElement(w, h)\n\n// after\nfunction canvasSupported(): boolean {\n  try {\n    return document.createElement('canvas').getContext('2d') !== null\n  } catch {\n    return false\n  }\n}\nif (!canvasSupported()) {\n  // fall back to direct MediaRecorder on the stream, no compositing\n  recorder = new Recorder(stream, options)\n} else {\n  composer = new CanvasStreamComposer(stream, w, h)\n}","handlingStrategy":"fallback","validationCode":"function canvas2dAvailable(): boolean {\n  try {\n    const c = document.createElement('canvas')\n    return typeof c.getContext === 'function' && c.getContext('2d') !== null\n  } catch {\n    return false\n  }\n}\nif (!canvas2dAvailable()) console.warn('Canvas 2D unavailable; recording will run without compositing')","typeGuard":"function has2dContext(canvas: HTMLCanvasElement): canvas is HTMLCanvasElement & { getContext: (t: '2d', o?: CanvasRenderingContext2DSettings) => CanvasRenderingContext2D } {\n  return canvas.getContext('2d') !== null\n}","tryCatchPattern":"let composer: CanvasStreamComposer | null = null\ntry {\n  composer = new CanvasStreamComposer(stream, width, height)\n} catch (err) {\n  if (err instanceof Error && err.message.includes('unable to get canvas context')) {\n    composer = null // degrade gracefully: record the raw stream instead\n    recorder = new Recorder(stream, options)\n  } else {\n    throw err\n  }\n}","preventionTips":["Check canvas 2D support before initializing the recorder composer","Ensure hardware acceleration is enabled in target browsers and test in policy-restricted environments","Cap canvas dimensions at reasonable sizes to avoid exceeding browser canvas limits","In Electron/webview apps, verify canvas and GPU flags during app startup diagnostics"],"tags":["browser","canvas","gpu","media-recording"],"backgroundTag":"canvas-context-unavailable","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}