remotion-dev/remotion · error · Error

Could not find number of channels

Error message

Could not find number of channels

What it means

Thrown by makeBaseMediaTrack() while turning an ISO Base Media (MP4/MOV/M4A) trak box into a track. The track tested positive for audio (trakBoxContainsAudio === true) but getNumberOfChannelsFromTrak() returned null, meaning the channel count could not be read from the audio sample entry. The parser refuses to invent a decoder-critical value, so it aborts the whole parse.

Source

Thrown at packages/media-parser/src/containers/iso-base-media/make-track.ts:64

	| MediaParserOtherTrack
	| null => {
	const tkhdBox = getTkhdBox(trakBox);

	const videoDescriptors = getVideoDescriptors(trakBox);
	const timescaleAndDuration = getTimescaleAndDuration(trakBox);

	if (!tkhdBox) {
		throw new Error('Expected tkhd box in trak box');
	}

	if (!timescaleAndDuration) {
		throw new Error('Expected timescale and duration in trak box');
	}

	if (trakBoxContainsAudio(trakBox)) {
		const numberOfChannels = getNumberOfChannelsFromTrak(trakBox);
		if (numberOfChannels === null) {
			throw new Error('Could not find number of channels');
		}

		const sampleRate = getSampleRate(trakBox);
		if (sampleRate === null) {
			throw new Error('Could not find sample rate');
		}

		const {codecString, description} = getAudioCodecStringFromTrak(trakBox);
		const codecPrivate =
			getCodecPrivateFromTrak(trakBox) ?? description ?? null;
		const codecEnum = getAudioCodecFromTrack(trakBox);

		const actual = getActualDecoderParameters({
			audioCodec: codecEnum,
			codecPrivate: codecPrivate ?? null,
			numberOfChannels,
			sampleRate,
		});

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Validate the file first with ffprobe <file> or MP4Box -info <file>. If ffprobe cannot read the channel count either, the file is broken.
  2. Re-mux the source: ffmpeg -i in.mp4 -c copy -map 0 -map_metadata 0 out.mp4; if that still fails, re-encode the audio: ffmpeg -i in.mp4 -c:v copy -c:a aac -b:a 128k out.mp4.
  3. Migrate to @remotion/mediabunny (parseMedia is deprecated per parse-media.ts:11); Mediabunny is more tolerant of non-standard atoms.
  4. If you only need video, remux without the audio track: ffmpeg -i in.mp4 -an -c:v copy video-only.mp4, then parse that.

Example fix

// before
const {tracks} = await parseMedia({src: brokenFile, reader: nodeReader});

// after
try {
  const {tracks} = await parseMedia({src: brokenFile, reader: nodeReader});
} catch (err) {
  if (err instanceof Error && /Could not find number of channels/.test(err.message)) {
    // audio sample entry is malformed: re-mux or re-encode audio with ffmpeg
    console.warn('Audio track unreadable, falling back to re-muxed file');
  } else {
    throw err;
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-validate the audio sample entry before parsing.
// Run ffprobe and check it reports a channel count for the audio stream:
//   ffprobe -v error -select_streams a:0 -show_entries stream=channels -of default=nw=1:nk=1 in.mp4
// Programmatically (Node):
import {execFileSync} from 'node:child_process';
function audioChannelsReadable(file: string): boolean {
  try {
    const out = execFileSync('ffprobe',
      ['-v','error','-select_streams','a:0','-show_entries','stream=channels','-of','default=nw=1:nk=1', file],
      {encoding: 'utf8'}); // 'N/A' or empty => unreadable
    return /^\d+$/.test(out.trim());
  } catch { return false; }
}

Type guard

// No structural type guard exists: parseMedia accepts a src (URL/File/Uint8Array),
// and the audio sample entry is a deep binary structure only inspectable by parsing.
// Treat parseMedia's own result/errors as the source of truth.
// => typeGuard: null

Try / catch

let tracks;
try {
  ({tracks} = await parseMedia({src, reader: nodeReader}));
} catch (err) {
  if (err instanceof Error && /Could not find number of channels/.test(err.message)) {
    // audio sample entry is malformed: re-mux/re-encode audio, or drop the track
    tracks = null;
  } else {
    throw err; // unknown failure: surface it
  }
}

Prevention

When it happens

Trigger: parseMedia({src}) on a file whose audio trak has a corrupt, truncated, or non-standard audio sample description: the stsd → mp4a (or other FourCC) entry is missing the sub-boxes (esds/wave/samplesize) from which channel count is derived. Also seen with audio codecs whose sample-entry layout this parser does not parse channel counts from.

Common situations: Partially downloaded or partially muxed files; M4A/MP4 produced by buggy or non-standard encoders; audio-only M4A with stripped atoms; obscure audio-in-mp4 codecs (e.g. some Opus/AMR variants) that the parser cannot fully introspect.

Related errors


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