remotion-dev/remotion · error · Error

The primary video track cannot be decoded.

Error message

The primary video track cannot be decoded.

What it means

A primary video track exists, but videoTrack.canDecode() returned false: the browser has no decoder for the track's codec/profile. Since frames cannot be decoded, video layer separation cannot proceed and the library throws. This is a browser WebCodecs capability limit, not a file corruption signal per se.

Source

Thrown at packages/video-matting/src/separate-video-layers.ts:262

const probeVideoInput = async ({
	input,
	videoQuality,
}: {
	input: Input;
	videoQuality: Quality;
}): Promise<{videoTrack: InputVideoTrack; width: number; height: number}> => {
	if (!(await input.canRead())) {
		throw new Error('The input is not a supported media file.');
	}

	const videoTrack = await input.getPrimaryVideoTrack();
	if (videoTrack === null) {
		throw new Error('The input does not contain a video track.');
	}

	if (!(await videoTrack.canDecode())) {
		throw new Error('The primary video track cannot be decoded.');
	}

	const [width, height] = await Promise.all([
		videoTrack.getDisplayWidth(),
		videoTrack.getDisplayHeight(),
	]);
	if (
		!Number.isInteger(width) ||
		width <= 0 ||
		!Number.isInteger(height) ||
		height <= 0
	) {
		throw new Error('The input video has invalid dimensions.');
	}

	const [canEncodeBase, canEncodeForeground] = await Promise.all([
		canEncodeVideo('vp9', {
			width,

View on GitHub (pinned to b2f4e34732)

Solutions

  1. Transcode the source to a universally decodable codec first (H.264 baseline/main in MP4, or VP8/VP9 in WebM).
  2. Test with the same file in another browser to confirm it is a codec-support issue.
  3. Use Mediabunny's codec support probing (e.g. getFirstEncodableVideoCodec / canDecode equivalents) to pre-check before calling.
  4. On iOS, ensure the HEVC video is exported as H.264 (Settings > Camera > Formats > Most Compatible).

Example fix

// before
await separateVideoLayers({src: hevcVideo.mov});
// after
await separateVideoLayers({src: await transcodeToH264(hevcVideo)});
Defensive patterns

Strategy: fallback

Validate before calling

const input = new Input({source: new BlobSource(file), formats: ALL_FORMATS});
const track = await input.getPrimaryVideoTrack();
if (track && !(await track.canDecode())) {
  file = await transcodeToH264(file); // pre-transcode before separating
}

Try / catch

try {
  await separateVideoLayers({src});
} catch (e) {
  if (e instanceof Error && e.message.includes('cannot be decoded')) {
    const transcoded = await transcodeToH264(src);
    return separateVideoLayers({src: transcoded});
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing an H.265/HEVC, VP9 profile without hardware/software decode support, AV1 in a browser without AV1, or an exotic codec (ProRes, MPEG-2) to separateVideoLayers in a browser lacking the decoder.

Common situations: iPhone-recorded HEVC .mov files in Chrome; 10-bit H.264 high profiles; Firefox builds without proprietary codecs; old Safari versions without VP9 decode.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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