remotion-dev/remotion · error · Error

Could not create a canvas. This API must run in a browser wi

Error message

Could not create a canvas. This API must run in a browser with OffscreenCanvas or the DOM available.

What it means

createVideoMattingCanvas needs a canvas to run the matting pipeline: it prefers OffscreenCanvas and falls back to document.createElement('canvas'). If neither OffscreenCanvas nor document exists (i.e. not running in a browser), it throws this Error. Video layer separation is a browser-only API requiring canvas support.

Source

Thrown at packages/video-matting/src/video-matting-canvas.ts:27

export const createVideoMattingCanvas = ({
	width,
	height,
}: {
	width: number;
	height: number;
}): VideoMattingCanvas => {
	if (typeof OffscreenCanvas !== 'undefined') {
		return new OffscreenCanvas(width, height);
	}

	if (typeof document !== 'undefined') {
		const canvas = document.createElement('canvas');
		canvas.width = width;
		canvas.height = height;
		return canvas;
	}

	throw new Error(
		'Could not create a canvas. This API must run in a browser with OffscreenCanvas or the DOM available.',
	);
};

export const getVideoMattingCanvasContext = (
	canvas: VideoMattingCanvas,
): VideoMattingCanvasContext => {
	const context = canvas.getContext('2d', {willReadFrequently: true});
	if (!context) {
		throw new Error('Could not create a 2D canvas context.');
	}

	return context as VideoMattingCanvasContext;
};

export const drawOpaqueBaseFrame = ({
	context,
	source,

View on GitHub (pinned to b2f4e34732)

Solutions

  1. Run the code only in a browser context — move the call into a client-side effect/handler, not module top-level or SSR.
  2. Guard with typeof document !== 'undefined' || typeof OffscreenCanvas !== 'undefined' before calling.
  3. In tests, either skip the test or use a browser-based test runner (Playwright) instead of jsdom.
  4. In web workers, target browsers supporting OffscreenCanvas in workers (Chrome 69+, Safari 16.4+).

Example fix

// before
// runs during SSR and crashes
export const loader = () => separateVideoLayers({src});
// after
export const loader = () => {
  if (typeof document === 'undefined') return null; // skip on server
  return separateVideoLayers({src});
};
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof OffscreenCanvas === 'undefined' && typeof document === 'undefined') {
  throw new Error('separateVideoLayers requires a browser environment');
}

Type guard

const canRunVideoMatting = (): boolean =>
  typeof OffscreenCanvas !== 'undefined' || typeof document !== 'undefined';

Try / catch

try {
  await separateVideoLayers({src});
} catch (e) {
  if (e instanceof Error && e.message.includes('OffscreenCanvas or the DOM')) {
    // not a browser: skip or reroute to server-side processing
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling separateVideoLayers from Node.js, a Web Worker without OffscreenCanvas (old browsers), SSR code (server-side rendering of a component that eagerly invokes the API), or a jsdom-based test environment lacking OffscreenCanvas and real canvas creation.

Common situations: Next.js SSR importing the function into a server route; Jest/jsdom tests; Node scripts; extremely old browsers or web workers in Safari < 16.4 where OffscreenCanvas is missing in workers.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


AI-assisted analysis of remotion-dev/remotion@b2f4e34732 (2026-09-09). Data as JSON: /api/errors/86c0594ffe77753f. Report an issue: GitHub.