remotion-dev/remotion · error · Error

Expected AAC codec private data

Error message

Expected AAC codec private data

What it means

Thrown by getActualDecoderParameters when an audio track is labeled codec 'aac' and codecPrivate is non-null, but codecPrivate.type is not 'aac-config'. The function only knows how to derive real channel count and sample rate from a properly shaped AAC-specific config blob; any other shape is a logic/data mismatch rather than a missing field. It is an internal contract violation: the upstream codecPrivate producer mislabeled the payload.

Source

Thrown at packages/media-parser/src/containers/iso-base-media/get-actual-number-of-channels.ts:41

	audioCodec: MediaParserAudioCodec;
	codecPrivate: MediaParserCodecData | null;
	numberOfChannels: number;
	sampleRate: number;
}): AudioDecoderConfig => {
	if (audioCodec !== 'aac') {
		return {
			numberOfChannels,
			sampleRate,
			codecPrivate,
		};
	}

	if (codecPrivate === null) {
		return {numberOfChannels, sampleRate, codecPrivate};
	}

	if (codecPrivate.type !== 'aac-config') {
		throw new Error('Expected AAC codec private data');
	}

	const parsed = parseAacCodecPrivate(codecPrivate.data);

	const actual = createAacCodecPrivate({
		...parsed,
		codecPrivate: codecPrivate.data,
	});

	return {
		numberOfChannels: parsed.channelConfiguration,
		sampleRate: parsed.sampleRate,
		codecPrivate: {type: 'aac-config', data: actual},
	};
};

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Re-mux the audio track with ffmpeg: `ffmpeg -i in.mp4 -c:a aac -b:a 128k out.mp4` to regenerate a clean esds.
  2. If you control the caller, narrow audioCodec before invoking getActualDecoderParameters: only pass AAC private data when codecPrivate.type === 'aac-config'.
  3. File a media-parser issue with the offending file; this typically indicates a parser regression.
  4. Wrap the call in try/catch and fall back to the original numberOfChannels/sampleRate when private-data parsing fails.

Example fix

// before
const actual = getActualDecoderParameters({ audioCodec, codecPrivate, numberOfChannels, sampleRate });

// after
const actual =
  audioCodec === 'aac' && codecPrivate && codecPrivate.type !== 'aac-config'
    ? { numberOfChannels, sampleRate, codecPrivate: null } // fall back: ignore mismatched private data
    : getActualDecoderParameters({ audioCodec, codecPrivate, numberOfChannels, sampleRate });
Defensive patterns

Strategy: type-guard

Validate before calling

import type {MediaParserCodecData} from '../../codec-data';
function isAacConfigPrivate(data: MediaParserCodecData | null): data is { type: 'aac-config'; data: Uint8Array } {
  return data !== null && data.type === 'aac-config';
}

Type guard

import type {MediaParserCodecData} from '../../codec-data';
function isAacCodecPrivate(data: MediaParserCodecData | null): boolean {
  return data === null || data.type === 'aac-config';
}
// Use before getActualDecoderParameters:
if (audioCodec === 'aac' && !isAacCodecPrivate(codecPrivate)) {
  codecPrivate = null; // discard mismatched private data
}

Try / catch

try {
  const actual = getActualDecoderParameters({ audioCodec, codecPrivate, numberOfChannels, sampleRate });
} catch (err) {
  if (/Expected AAC codec private data/i.test(String(err?.message))) {
    // Fall back to declared channel count; ignore the bad private data
    return { numberOfChannels, sampleRate, codecPrivate: null };
  }
  throw err;
}

Prevention

When it happens

Trigger: Reachable when getCodecPrivateFromTrak or the esds parser yields a codecPrivate object whose type is something like 'av1-config' or a raw buffer wrapper, while getAudioCodecFromTrack separately classified the track as AAC. Most often a parser bug or a malformed esds box where the descriptor type does not match the audio codec family.

Common situations: MP4 files with non-standard or corrupted esds (Elementary Stream Descriptor) boxes. Files where the audio object type is ambiguous and one code path labels it AAC while another attaches non-AAC codec private data. Mismatch after a partial media-parser upgrade that changed the codecPrivate discriminated union.

Related errors


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