remotion-dev/remotion · error · Error

Free bitrate not supported

Error message

Free bitrate not supported

What it means

Thrown while parsing an MP3 frame header when the 4-bit bitrate index decodes to the 'free' bitrate mode (index 0000). In MP3, 'free' means the bitrate is not encoded in the frame and must be derived from frame size; @remotion/media-parser declines to do that and rejects such files outright. The check happens in parse-packet-header.ts right after getBitrateKB returns the sentinel string 'free'.

Source

Thrown at packages/media-parser/src/containers/mp3/parse-packet-header.ts:224

		throw new Error('Expected Layer I, II or III');
	}

	const layer = layerBits === 0b11 ? 1 : layerBits === 0b10 ? 2 : 3;

	iterator.getBits(1); // 0b1 means that there is no CRC, 0b0 means there is. Not validating checksum though

	const bitrateIndex = iterator.getBits(4);
	const bitrateInKbit = getBitrateKB({
		bits: bitrateIndex,
		mpegVersion,
		level: layer as Level,
	});
	if (bitrateInKbit === 'bad') {
		throw new Error('Invalid bitrate');
	}

	if (bitrateInKbit === 'free') {
		throw new Error('Free bitrate not supported');
	}

	const samplingFrequencyIndex = iterator.getBits(2);

	const baseSampleRate = getSamplingFrequency({
		bits: samplingFrequencyIndex,
		mpegVersion,
	});
	const sampleRate =
		audioVersionId === 0b00 ? baseSampleRate / 2 : baseSampleRate;
	const padding = Boolean(iterator.getBits(1));
	iterator.getBits(1); // private bit
	const channelMode = iterator.getBits(2); // channel mode
	iterator.getBits(2); // mode extension
	iterator.getBits(1); // copyright
	iterator.getBits(1); // original
	iterator.getBits(2); // emphasis

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Re-encode the MP3 with a standard fixed bitrate (e.g. 128/192/320 kbit) using a mainstream encoder like LAME or ffmpeg: ffmpeg -i input.mp3 -c:a libmp3lame -b:a 192k output.mp3
  2. If the file is valid free-format MP3 that you must support, pre-scan and reject it before passing to parseMediaStream so the error is handled upstream.
  3. Verify the file is actually MPEG audio and not a mislabeled container by checking the first frame sync (0xFFE/0xFFF) before invoking the parser.

Example fix

// before
await parseMediaStream({src: freeFormatMp3Url, fields: {durationInSeconds: true}});

// after: re-encode to a constrained-bitrate MP3 first
// ffmpeg -i input.mp3 -c:a libmp3lame -b:a 192k output.mp3
await parseMediaStream({src: 'output.mp3', fields: {durationInSeconds: true}});
Defensive patterns

Strategy: validation

Validate before calling

// Read the 4-bit bitrate index of the first MP3 frame and reject 'free' (index 0) up front.
function isFreeBitrateMp3(firstFrame: Uint8Array): boolean {
  if (firstFrame.length < 4) return false;
  const b2 = firstFrame[2];
  const bitrateIndex = (b2 >> 4) & 0x0f;
  return bitrateIndex === 0b0000; // 'free' bitrate
}
if (isFreeBitrateMp3(firstFrame)) {
  throw new Error('Rejecting free-bitrate MP3 before parsing');
}

Type guard

null

Try / catch

try {
  await parseMediaStream({src: mp3Url, fields: {durationInSeconds: true}});
} catch (err) {
  if (err instanceof Error && err.message === 'Free bitrate not supported') {
    // re-encode to a fixed-bitrate MP3, then retry
  } else throw err;
}

Prevention

When it happens

Trigger: Parsing an MP3 whose frame header has bitrateIndex bits == 0b0000. Most common with files produced by experimental/old encoders (LAME --cbr with free-format, or custom encoders) or with the first frame being a non-MPEG filler.

Common situations: Hand-edited or truncated MP3s, free-format MP3 files, MP3s wrapped/transcoded by toolchains that emit free-bitrate frames, or random/corrupt data misidentified as MP3.

Related errors


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