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
- Validate the file first with ffprobe <file> or MP4Box -info <file>. If ffprobe cannot read the channel count either, the file is broken.
- 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.
- Migrate to @remotion/mediabunny (parseMedia is deprecated per parse-media.ts:11); Mediabunny is more tolerant of non-standard atoms.
- 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
- Pre-validate every source with ffprobe/MP4Box before passing it to parseMedia.
- Prefer re-muxed/clean sources from ffmpeg over ad-hoc or hand-edited files.
- Migrate new code to @remotion/mediabunny; parseMedia is deprecated and less tolerant.
- Keep a try/catch around every parseMedia() call when the input set is untrusted.
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
- Could not find sample rate
- No video sample
- Could not find video codec
- Unsupported AVCC version ${confVersion}
- Unexpected sampling frequency index ${samplingFrequencyIndex
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/6fdf3d007d58f1ac.
Report an issue: GitHub.