remotion-dev/remotion · error · Error

Could not find sample rate

Error message

Could not find sample rate

What it means

Thrown by makeBaseMediaTrack() immediately after the channel-count check. The track is detected as audio, but getSampleRate() returned null, so the sample rate could not be extracted from the audio sample entry (typically the mp4a esds/decoder-specific info). Sample rate is required to configure a WebCodecs AudioDecoder, so the parser aborts rather than guess.

Source

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

	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,
		});

		return {
			type: 'audio',
			trackId: tkhdBox.trackId,
			originalTimescale: timescaleAndDuration.timescale,

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Pre-validate with ffprobe <file> to confirm it reports a sample rate; if not, the file is malformed.
  2. Re-mux cleanly: ffmpeg -i in.mp4 -c copy out.mp4, or re-encode audio: ffmpeg -i in.mp4 -c:v copy -c:a aac out.mp4.
  3. Switch to @remotion/mediabunny (parseMedia is deprecated).
  4. Drop the audio track if unused: ffmpeg -i in.mp4 -an -c:v copy out.mp4.

Example fix

// before
await parseMedia({src, reader: nodeReader, onAudioTrack: () => {}});

// after
try {
  await parseMedia({src, reader: nodeReader, onAudioTrack: () => {}});
} catch (err) {
  if (err instanceof Error && /Could not find sample rate/.test(err.message)) {
    // audio sample entry unreadable; re-encode the audio stream
  } else throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm the audio stream reports a sample rate via ffprobe before parsing:
//   ffprobe -v error -select_streams a:0 -show_entries stream=sample_rate -of default=nw=1:nk=1 in.mp4
import {execFileSync} from 'node:child_process';
function audioSampleRateReadable(file: string): boolean {
  try {
    const out = execFileSync('ffprobe',
      ['-v','error','-select_streams','a:0','-show_entries','stream=sample_rate','-of','default=nw=1:nk=1', file],
      {encoding: 'utf8'});
    return /^\d+$/.test(out.trim()) && Number(out.trim()) > 0;
  } catch { return false; }
}

Type guard

// src is a URL/File/Uint8Array; the audio sample entry is binary and not
// type-guardable from the caller. No narrowing function is possible.
// => typeGuard: null

Try / catch

try {
  await parseMedia({src, reader: nodeReader, onAudioTrack: () => {}});
} catch (err) {
  if (err instanceof Error && /Could not find sample rate/.test(err.message)) {
    // audio decoder-private data unreadable: re-encode audio or skip it
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: parseMedia({src}) on an MP4/MOV/M4A whose audio sample entry lacks or has a corrupt esds/wave sub-box carrying the sample-rate field. Common when the mp4a box is present (so the track is flagged audio) but its decoder-config payload is missing or truncated.

Common situations: Files with stripped/rewritten atoms, incomplete captures, screen recordings with malformed audio, or audio codecs whose decoder-private data this parser does not understand.

Related errors


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