remotion-dev/remotion · error · Error
Failed to acquire 2D context for output canvas
Error message
Failed to acquire 2D context for output canvas
What it means
Thrown by the imperative effect-chain runner when output.getContext('2d') returns null on the final compositing canvas (HTMLCanvasElement or OffscreenCanvas) during the no-effects / in-place branch. A canvas can only host one context type; once a 'webgl' or 'webgpu' context has been acquired on it, getContext('2d') permanently returns null, and a lost-context state can also produce null.
Source
Thrown at packages/core/src/effects/run-effect-chain.ts:108
// on `params` so it flows through code/drag override merging.
const enabledEffects = effects.filter(
(e) => !(e.params as {disabled?: boolean}).disabled,
);
const runs = groupByBackend(enabledEffects);
let currentImage: CanvasImageSource = source;
let lastTarget: HTMLCanvasElement | null = null;
if (runs.length === 0) {
// In-place pipeline (e.g. <HtmlInCanvas>: drawElementImage into the same
// surface, no further effects) — the bitmap is already on `output`.
if (source === output) {
return true;
}
const ctx = output.getContext('2d');
if (!ctx) {
throw new Error('Failed to acquire 2D context for output canvas');
}
ctx.clearRect(0, 0, width, height);
ctx.drawImage(currentImage, 0, 0, width, height);
return true;
}
let needsGpuDevice = false;
for (const run of runs) {
if (run.backend === 'webgpu') {
needsGpuDevice = true;
break;
}
}
const gpuDevice = needsGpuDevice ? await getGpuDevice() : null;
if (isCancelled()) {
return false;View on GitHub (pinned to 78fe4bb3fd)
Solutions
- Ensure the canvas passed as `output` has never acquired a 'webgl' or 'webgpu' context — the effect chain allocates intermediate WebGL canvases itself via CanvasPool, so the output canvas must stay 2D-only.
- If using OffscreenCanvas, do not transfer it from a worker with an attached context; create a fresh OffscreenCanvas on the side that calls runEffectChain.
- On intermittent GPU-process crashes, recreate the output canvas element (the old one is poisoned) before retrying the chain.
- If you authored a custom EffectDefinition whose setup() calls target.getContext('webgl'), make sure it operates on a pooled intermediate canvas, not on `output`.
Example fix
// before: reusing a canvas that already has webgl
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
runEffectChain({output: canvas, /* ... */}); // throws
// after: keep a dedicated 2D-only output canvas
const output = document.createElement('canvas');
runEffectChain({output, /* ... */}); Defensive patterns
Strategy: validation
Validate before calling
// Before calling runEffectChain, confirm `output` can still yield a 2D context.
function canAcquire2D(output: HTMLCanvasElement | OffscreenCanvas): boolean {
// Probe without poisoning the canvas: getContext on a canvas that already
// has a different context type returns null without changing state only
// for the *first* acquisition — so only call this on a fresh canvas.
return output.getContext('2d') !== null;
}
if (!canAcquire2D(output)) {
output = document.createElement('canvas'); // allocate a fresh 2D canvas
} Type guard
function isFresh2DCanvas(c: HTMLCanvasElement | OffscreenCanvas): boolean {
// Heuristic: a canvas that has never acquired another context will return a 2D context.
// Do NOT call this on a canvas you intend to keep WebGL on.
return c.getContext('2d') !== null;
} Prevention
- Never reuse a WebGL/WebGPU canvas as the effect-chain output; keep a dedicated 2D composite canvas.
- Let Remotion's CanvasPool own intermediate WebGL surfaces.
- On GPU-process crash, discard the poisoned canvas and allocate a new one before retrying.
When it happens
Trigger: Calling runEffectChain with an `output` canvas that already obtained a WebGL/WebGPU context; or passing an OffscreenCanvas that was transferred from a worker where its context was already detached; or running in an environment where the GPU process crashed and the 2D context cannot be re-acquired.
Common situations: Reusing the same canvas element for both a WebGL/WebGPU effect and the final 2D composite; browser GPU-process crash mid-render; headless render where the canvas pool hands back a canvas that previously held a non-2D context.
Related errors
- Failed to create WebGL shader
- Failed to create WebGL program
- Failed to create WebGL buffer
- Failed to create WebGL texture
- Failed to create WebGL shader
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/e2de642be7588192.
Report an issue: GitHub.