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

  1. 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.
  2. If using OffscreenCanvas, do not transfer it from a worker with an attached context; create a fresh OffscreenCanvas on the side that calls runEffectChain.
  3. On intermittent GPU-process crashes, recreate the output canvas element (the old one is poisoned) before retrying the chain.
  4. 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

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


AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12). Data as JSON: /api/errors/e2de642be7588192. Report an issue: GitHub.