{"record":{"id":"2a774e1124e37749","repo":"remotion-dev/remotion","slug":"the-primary-video-track-cannot-be-decoded","errorCode":null,"errorMessage":"The primary video track cannot be decoded.","messagePattern":"The primary video track cannot be decoded\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/video-matting/src/separate-video-layers.ts","lineNumber":262,"sourceCode":"\nconst probeVideoInput = async ({\n\tinput,\n\tvideoQuality,\n}: {\n\tinput: Input;\n\tvideoQuality: Quality;\n}): Promise<{videoTrack: InputVideoTrack; width: number; height: number}> => {\n\tif (!(await input.canRead())) {\n\t\tthrow new Error('The input is not a supported media file.');\n\t}\n\n\tconst videoTrack = await input.getPrimaryVideoTrack();\n\tif (videoTrack === null) {\n\t\tthrow new Error('The input does not contain a video track.');\n\t}\n\n\tif (!(await videoTrack.canDecode())) {\n\t\tthrow new Error('The primary video track cannot be decoded.');\n\t}\n\n\tconst [width, height] = await Promise.all([\n\t\tvideoTrack.getDisplayWidth(),\n\t\tvideoTrack.getDisplayHeight(),\n\t]);\n\tif (\n\t\t!Number.isInteger(width) ||\n\t\twidth <= 0 ||\n\t\t!Number.isInteger(height) ||\n\t\theight <= 0\n\t) {\n\t\tthrow new Error('The input video has invalid dimensions.');\n\t}\n\n\tconst [canEncodeBase, canEncodeForeground] = await Promise.all([\n\t\tcanEncodeVideo('vp9', {\n\t\t\twidth,","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/remotion-dev/remotion/blob/b2f4e34732f3c6c222ea029413e22dc402218cd7/packages/video-matting/src/separate-video-layers.ts#L244-L280","documentation":"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.","triggerScenarios":"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.","commonSituations":"iPhone-recorded HEVC .mov files in Chrome; 10-bit H.264 high profiles; Firefox builds without proprietary codecs; old Safari versions without VP9 decode.","solutions":["Transcode the source to a universally decodable codec first (H.264 baseline/main in MP4, or VP8/VP9 in WebM).","Test with the same file in another browser to confirm it is a codec-support issue.","Use Mediabunny's codec support probing (e.g. getFirstEncodableVideoCodec / canDecode equivalents) to pre-check before calling.","On iOS, ensure the HEVC video is exported as H.264 (Settings > Camera > Formats > Most Compatible)."],"exampleFix":"// before\nawait separateVideoLayers({src: hevcVideo.mov});\n// after\nawait separateVideoLayers({src: await transcodeToH264(hevcVideo)});","handlingStrategy":"fallback","validationCode":"const input = new Input({source: new BlobSource(file), formats: ALL_FORMATS});\nconst track = await input.getPrimaryVideoTrack();\nif (track && !(await track.canDecode())) {\n  file = await transcodeToH264(file); // pre-transcode before separating\n}","typeGuard":null,"tryCatchPattern":"try {\n  await separateVideoLayers({src});\n} catch (e) {\n  if (e instanceof Error && e.message.includes('cannot be decoded')) {\n    const transcoded = await transcodeToH264(src);\n    return separateVideoLayers({src: transcoded});\n  }\n  throw e;\n}","preventionTips":["Prefer H.264/MP4 or VP9/WebM sources; avoid HEVC .mov from iPhones.","Pre-check canDecode() on the primary video track before heavy work.","Document supported codecs in your upload UI."],"tags":["mediabunny","codec","webcodecs","browser-support"],"backgroundTag":"unsupported-operation","analyzedSha":"b2f4e34732f3c6c222ea029413e22dc402218cd7","analyzedAt":"2026-09-09T13:27:51.281Z","contentChangedAt":"2026-09-09T13:27:51.281Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}