{"record":{"id":"dadcd464795a6819","repo":"remotion-dev/remotion","slug":"could-not-create-the-lut-preview-canvas","errorCode":null,"errorMessage":"Could not create the LUT preview canvas.","messagePattern":"Could not create the LUT preview canvas\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/studio/src/components/LutPreview.tsx","lineNumber":201,"sourceCode":"\t\t\t}\n\n\t\t\timage.src = sampleImage;\n\t\t\ttry {\n\t\t\t\tawait image.decode();\n\t\t\t} catch {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'Could not load the LUT sample image. Check your internet connection.',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (controller.signal.aborted) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst before = beforeRef.current?.getContext('2d');\n\t\t\tconst after = afterRef.current?.getContext('2d');\n\t\t\tif (!before || !after) {\n\t\t\t\tthrow new Error('Could not create the LUT preview canvas.');\n\t\t\t}\n\n\t\t\tbefore.drawImage(image, 0, 0, previewWidth, previewHeight);\n\t\t\tconst pixels = before.getImageData(0, 0, previewWidth, previewHeight);\n\t\t\tapplyCubeLut(pixels.data, lut);\n\t\t\tafter.putImageData(pixels, 0, 0);\n\t\t\tsetState({type: 'loaded'});\n\t\t};\n\n\t\tload().catch((error: unknown) => {\n\t\t\tif (!controller.signal.aborted) {\n\t\t\t\tsetState({\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\t});\n\t\t\t}\n\t\t});\n","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/remotion-dev/remotion/blob/46a3a6bf13ca367376ff18bbb06dae2e87e0d068/packages/studio/src/components/LutPreview.tsx#L183-L219","documentation":"After the LUT and sample image load, LutPreview draws to the before/after <canvas> elements via getContext('2d'). If either canvas ref is unmounted or its 2D context cannot be created (e.g. the canvas was replaced, or the browser already assigned a different context type), this error is thrown.","triggerScenarios":"The load() flow completes after the component unmounted or re-rendered such that beforeRef/afterRef.current is null or the canvas getContext('2d') returns null — typically due to an aborted-but-completed race or calling getContext with a different context type earlier.","commonSituations":"Fast toggling of the LUT preview panel mid-load; React StrictMode double-mounting racing with the async load; custom code calling getContext('webgl') on the same canvas first.","solutions":["Ensure the abort check (controller.signal.aborted) runs right before canvas access; re-check after image.decode() and LUT parse.","Verify nothing calls getContext('webgl'/'bitmaprenderer') on the before/after canvases before '2d'.","Reproduce with React StrictMode disabled to confirm it is a mount/unmount race, then guard with a mountedRef.","Update Studio to the latest version if this occurs spontaneously during normal preview use."],"exampleFix":"// before\nconst before = beforeRef.current?.getContext('2d');\n// after\nif (controller.signal.aborted) return;\nconst before = beforeRef.current?.getContext('2d');","handlingStrategy":"type-guard","validationCode":"if (!beforeRef.current || !afterRef.current) return; // skip drawing when unmounted","typeGuard":"const get2d = (c: HTMLCanvasElement | null): CanvasRenderingContext2D | null =>\n  c ? c.getContext('2d') : null;","tryCatchPattern":"try {\n  drawPreview();\n} catch (e) {\n  if (e.message === 'Could not create the LUT preview canvas.') return; // unmounted race\n  throw e;\n}","preventionTips":["Always check controller.signal.aborted after each await before touching refs.","Never request a non-2d context on the preview canvases.","Guard async completion paths with a mounted flag."],"tags":["canvas","react","race-condition","lut"],"backgroundTag":"invalid-state-transition","analyzedSha":"46a3a6bf13ca367376ff18bbb06dae2e87e0d068","analyzedAt":"2026-09-18T00:12:20.256Z","contentChangedAt":"2026-09-18T00:12:20.256Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}