{"record":{"id":"b4fda24c553bf3cf","repo":"remotion-dev/remotion","slug":"failed-to-create-output-canvas-context","errorCode":null,"errorMessage":"Failed to create output canvas context","messagePattern":"Failed to create output canvas context","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/transitions/src/html-in-canvas-presentation.tsx","lineNumber":120,"sourceCode":"\t\t};\n\t}, [instance]);\n\n\tconst chainState = Internals.useEffectChainState();\n\tconst {delayRender, continueRender, cancelRender} = useDelayRender();\n\n\tconst draw: DrawFunction = useCallback(\n\t\tasync (prevImage, nextImage, progress) => {\n\t\t\tconst outputCanvas = outputCanvasRef.current;\n\t\t\tif (!outputCanvas) {\n\t\t\t\tthrow new Error('Canvas not found');\n\t\t\t}\n\n\t\t\tconst handle = delayRender('onPaint');\n\t\t\ttry {\n\t\t\t\tconst clearOutput = () => {\n\t\t\t\t\tconst context = outputCanvas.getContext('2d');\n\t\t\t\t\tif (!context) {\n\t\t\t\t\t\tthrow new Error('Failed to create output canvas context');\n\t\t\t\t\t}\n\n\t\t\t\t\tcontext.clearRect(0, 0, outputCanvas.width, outputCanvas.height);\n\t\t\t\t};\n\n\t\t\t\tif (!prevImage && !nextImage) {\n\t\t\t\t\tinstance.clear();\n\t\t\t\t\tclearOutput();\n\t\t\t\t\tcontinueRender(handle);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst width = prevImage?.width ?? nextImage?.width ?? 0;\n\t\t\t\tconst height = prevImage?.height ?? nextImage?.height ?? 0;\n\n\t\t\t\tif (width === 0 || height === 0) {\n\t\t\t\t\tinstance.clear();\n\t\t\t\t\tclearOutput();","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/remotion-dev/remotion/blob/a6a7485a9aeb04219510fbe4874f8941486424df/packages/transitions/src/html-in-canvas-presentation.tsx#L102-L138","documentation":"In @remotion/transitions' HTML-in-canvas presentation, clearOutput obtains a 2D rendering context from the output canvas via getContext('2d') to clear it between draws. If the browser returns null — no 2D context can be created — this error is thrown inside the onPaint delayRender scope. This typically means the canvas is already bound to a different context type or the canvas cannot provide a context at all.","triggerScenarios":"Calling getContext('2d') on a canvas that previously had getContext('webgl'/'bitmaprenderer') called on it (a canvas returns null for all other context types after the first); passing a detached/off-DOM or zero-sized canvas in an environment without a real document; browser failing context creation under memory pressure.","commonSituations":"Mixing the transitions canvas presentation with other code (three.js, WebGL preview) that grabbed a different context on the same canvas element; rendering headless (server-side) where the canvas is not backed by a document; hardware-acceleration disabled in the rendering browser causing 2D context creation to fail.","solutions":["Ensure nothing else calls getContext with a non-2d type on the same outputCanvas; give the presentation its own dedicated canvas element","Create a fresh canvas for the presentation instead of reusing one from elsewhere in the app","Verify the code runs in a browser with a real DOM document (not SSR) and the canvas is attached/has non-zero width/height","Enable GPU/hardware acceleration (or add --enable-unsafe-swiftshader / software GL flags) in headless Chrome if context creation fails there","Wrap the paint work so the error surfaces with the delayRender handle properly released (use continueRender in a catch/finally) to avoid a stuck render"],"exampleFix":"// before\nconst context = outputCanvas.getContext('2d'); // null if canvas already used for webgl\nif (!context) throw new Error('Failed to create output canvas context');\n// after\nconst outputCanvas = document.createElement('canvas'); // dedicated canvas, never handed to webgl\nconst context = outputCanvas.getContext('2d');\nif (!context) throw new Error('Failed to create output canvas context');","handlingStrategy":"try-catch","validationCode":"function canProvide2DContext(canvas: HTMLCanvasElement): boolean {\n  // A canvas can only ever yield one context type; probe safely by checking existing state.\n  return canvas instanceof HTMLCanvasElement && canvas.width > 0 && canvas.height > 0;\n}","typeGuard":"function has2DContext(canvas: HTMLCanvasElement): canvas is HTMLCanvasElement & { getContext: (t: '2d') => CanvasRenderingContext2D } {\n  return canvas.getContext('2d') !== null;\n}","tryCatchPattern":"const handle = delayRender('onPaint');\ntry {\n  const context = outputCanvas.getContext('2d');\n  if (!context) throw new Error('Failed to create output canvas context');\n  context.clearRect(0, 0, outputCanvas.width, outputCanvas.height);\n  continueRender(handle);\n} catch (err) {\n  continueRender(handle);\n  console.error('Canvas 2D context unavailable; use a fresh dedicated canvas.', err);\n}","preventionTips":["Never call getContext('2d') on a canvas that has been used with webgl, webgpu, or bitmaprenderer — allocate a separate canvas per context type","Create the output canvas with document.createElement and attach it to the DOM before painting","Ensure rendering happens in a real browser context (no SSR) with hardware acceleration or software-GL available in headless Chrome","Always pair delayRender with continueRender in finally so a context failure cannot hang the render forever"],"tags":["canvas","browser","rendering","transitions"],"backgroundTag":"canvas-context-unavailable","analyzedSha":"a6a7485a9aeb04219510fbe4874f8941486424df","analyzedAt":"2026-09-02T16:25:19.997Z","contentChangedAt":"2026-09-02T16:25:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}