remotion-dev/remotion · error

Invalid syncword: ${syncWord}

Error message

Invalid syncword: ${syncWord}

What it means

Thrown by the ADTS AAC parser (parseAac) when the first 12 bits of a frame are not the sync word 0xFFF. ADTS (Audio Data Transport Stream) frames must begin with this 12-bit sync pattern; its absence means the byte stream is either not ADTS AAC, is corrupted, or the parser's read position has drifted and is no longer aligned to a frame boundary.

Source

Thrown at packages/media-parser/src/containers/aac/parse-aac.ts:19

import {
	createAacCodecPrivate,
	getSampleRateFromSampleFrequencyIndex,
	mapAudioObjectTypeToCodecString,
} from '../../aac-codecprivate';
import {convertAudioOrVideoSampleToWebCodecsTimestamps} from '../../convert-audio-or-video-sample';
import type {ParseResult} from '../../parse-result';
import {registerAudioTrack} from '../../register-track';
import type {ParserState} from '../../state/parser-state';
import {WEBCODECS_TIMESCALE} from '../../webcodecs-timescale';

export const parseAac = async (state: ParserState): Promise<ParseResult> => {
	const {iterator} = state;
	const startOffset = iterator.counter.getOffset();

	iterator.startReadingBits();
	const syncWord = iterator.getBits(12);
	if (syncWord !== 0xfff) {
		throw new Error('Invalid syncword: ' + syncWord);
	}

	const id = iterator.getBits(1);
	if (id !== 0) {
		throw new Error('Only supporting MPEG-4 for .aac');
	}

	const layer = iterator.getBits(2);
	if (layer !== 0) {
		throw new Error('Only supporting layer 0 for .aac');
	}

	const protectionAbsent = iterator.getBits(1); // protection absent
	const audioObjectType = iterator.getBits(2); // 1 = 'AAC-LC'

	const samplingFrequencyIndex = iterator.getBits(4);
	const sampleRate = getSampleRateFromSampleFrequencyIndex(
		samplingFrequencyIndex,

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Verify the file is genuinely raw ADTS AAC: `ffprobe input.aac` and confirm it reports 'ADTS AAC'.
  2. If the file is MP4/M4A-wrapped, remove the .aac extension or pass the correct container; parseMedia auto-detects containers.
  3. Re-mux or re-extract raw AAC: `ffmpeg -i input.mp4 -c:a copy -f adts output.aac`.
  4. Switch to Mediabunny (https://www.remotion.dev/docs/mediabunny/metadata) for more robust parsing.
  5. Report the file to Remotion if ffprobe can parse it but parseMedia cannot.
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check: verify file starts with ADTS sync word 0xFFF
import {readFile} from 'fs/promises';

async function isValidAdtsAac(filePath: string): Promise<boolean> {
  const buf = await readFile(filePath);
  if (buf.length < 2) return false;
  return (buf[0] === 0xff) && (buf[1] & 0xf0) === 0xf0;
}

Try / catch

try {
  const result = await parseMedia({src, fields: {/* ... */}});
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Invalid syncword')) {
    console.error('File is not valid ADTS AAC. Verify the format with: ffprobe <file>');
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling parseMedia on a .aac file (or raw ADTS stream) where the first 12 bits at the parse position are not 0xFFF. Occurs with non-ADTS streams (e.g. raw AAC frames without transport headers, or MP4-wrapped AAC being read as raw), truncated files, or bit-flipped/corrupted headers.

Common situations: Passing an MP4/M4A file that contains AAC inside an MP4 container but is being parsed as a raw .aac stream. Files with corrupted headers from incomplete downloads. Files that are actually a different format but have a .aac extension. Files with padding or metadata prepended before the first ADTS frame.

Related errors


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