remotion-dev/remotion · error · Error
Could not create the LUT preview canvas.
Error message
Could not create the LUT preview canvas.
What it means
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.
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.
Example fix
// before
const before = beforeRef.current?.getContext('2d');
// after
if (controller.signal.aborted) return;
const before = beforeRef.current?.getContext('2d'); Defensive patterns
Strategy: type-guard
Validate before calling
if (!beforeRef.current || !afterRef.current) return; // skip drawing when unmounted
Type guard
const get2d = (c: HTMLCanvasElement | null): CanvasRenderingContext2D | null =>
c ? c.getContext('2d') : null; Try / catch
try {
drawPreview();
} catch (e) {
if (e.message === 'Could not create the LUT preview canvas.') return; // unmounted race
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- No "src" prop was passed to
- A value of `undefined` was passed to the `component` prop…
- A value of `undefined` was passed to the `lazyComponent`…
- AbsoluteTimeContext is not available. This hook must be…
- animationData should be provided as an object. If you only…
AI-assisted analysis of remotion-dev/remotion@46a3a6bf13 (2026-09-18).
Data as JSON: /api/errors/dadcd464795a6819.
Report an issue: GitHub.
Appendix: source
Thrown at packages/studio/src/components/LutPreview.tsx:201
}
image.src = sampleImage;
try {
await image.decode();
} catch {
throw new Error(
'Could not load the LUT sample image. Check your internet connection.',
);
}
if (controller.signal.aborted) {
return;
}
const before = beforeRef.current?.getContext('2d');
const after = afterRef.current?.getContext('2d');
if (!before || !after) {
throw new Error('Could not create the LUT preview canvas.');
}
before.drawImage(image, 0, 0, previewWidth, previewHeight);
const pixels = before.getImageData(0, 0, previewWidth, previewHeight);
applyCubeLut(pixels.data, lut);
after.putImageData(pixels, 0, 0);
setState({type: 'loaded'});
};
load().catch((error: unknown) => {
if (!controller.signal.aborted) {
setState({
type: 'error',
error: error instanceof Error ? error.message : String(error),
});
}
});
View on GitHub (pinned to 46a3a6bf13)