remotion-dev/remotion · error · Error

Expected remaining bytes to be 0, got ${remaining}

Error message

Expected remaining bytes to be 0, got ${remaining}

What it means

Thrown at the end of parseMdhd() (media header box). After reading all defined mdhd fields for the box's version, leftover bytes remain: size - (bytesConsumed) !== 0. The box's declared size does not match the byte count the spec mandates, so the parser treats the box as malformed and aborts.

Source

Thrown at packages/media-parser/src/containers/iso-base-media/mdhd.ts:46

	// creation time
	const creationTime =
		version === 1 ? Number(data.getUint64()) : data.getUint32();

	// modification time
	const modificationTime =
		version === 1 ? Number(data.getUint64()) : data.getUint32();

	const timescale = data.getUint32();
	const duration = version === 1 ? data.getUint64() : data.getUint32();

	const language = data.getUint16();

	// quality
	const quality = data.getUint16();

	const remaining = size - (data.counter.getOffset() - fileOffset);
	if (remaining !== 0) {
		throw new Error(`Expected remaining bytes to be 0, got ${remaining}`);
	}

	return {
		type: 'mdhd-box',
		duration: Number(duration),
		timescale,
		version,
		language,
		quality,
		creationTime,
		modificationTime,
	};
};

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Re-mux with a compliant tool: ffmpeg -i in.mp4 -c copy out.mp4 (this rebuilds boxes with correct sizes).
  2. Validate with MP4Box -info in.mp4 or ffprobe; both flag box-size inconsistencies.
  3. Migrate to @remotion/mediabunny (parseMedia is deprecated) which may tolerate the mismatch.
  4. Obtain a fresh copy of the source file if you suspect download corruption.

Example fix

// before
const {durationInSeconds} = await parseMedia({src, reader: nodeReader});

// after
try {
  const {durationInSeconds} = await parseMedia({src, reader: nodeReader});
} catch (err) {
  if (err instanceof Error && /Expected remaining bytes to be 0/.test(err.message)) {
    // mdhd box size mismatch — re-mux with ffmpeg to rebuild boxes
  } else throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Have ffprobe/MP4Box sanity-check the file before parsing; box-size
// inconsistencies surface there as warnings/errors:
//   MP4Box -info in.mp4
//   ffprobe -v warning in.mp4
import {execFileSync} from 'node:child_process';
function fileLooksIntact(file: string): boolean {
  try {
    execFileSync('ffprobe', ['-v','warning','-hide_banner', file], {encoding: 'utf8', stdio:'pipe'});
    return true;
  } catch { return false; }
}

Type guard

// mdhd box correctness is a deep binary property; not type-guardable by the caller.
// => typeGuard: null

Try / catch

try {
  await parseMedia({src, reader: nodeReader});
} catch (err) {
  if (err instanceof Error && /Expected remaining bytes to be 0/.test(err.message)) {
    // mdhd size mismatch — re-mux with ffmpeg
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: parseMedia({src}) on an MP4/MOV/M4A whose mdhd box size is inconsistent with its version-0 or version-1 field layout — e.g. an mdhd with extra trailing bytes, a version this parser did not account for, or a size field that was corrupted/truncated.

Common situations: Files written by non-compliant muxers that pad or truncate boxes; edited/patched MP4s; corrupted downloads where the mdhd size field is wrong.

Related errors


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