remotion-dev/remotion · error · Error

expected 0 bytes ${bytesRemaining}

Error message

expected 0 bytes ${bytesRemaining}

What it means

Thrown at the end of parseMvhd() (movie header box). After reading every defined mvhd field for its version, leftover bytes remain: size - (bytesConsumed) !== 0. The declared mvhd size does not match the spec-mandated field layout, so the parser treats the box as malformed and aborts.

Source

Thrown at packages/media-parser/src/containers/iso-base-media/moov/mvhd.ts:108

		iterator.getFixedPointSigned1616Number(),
		iterator.getFixedPointSigned1616Number(),
		iterator.getFixedPointSigned230Number(),
		iterator.getFixedPointSigned1616Number(),
		iterator.getFixedPointSigned1616Number(),
		iterator.getFixedPointSigned230Number(),
	];

	// pre-defined
	iterator.discard(4 * 6);

	// next track id
	const nextTrackId = iterator.getUint32();

	volumeView.destroy();

	const bytesRemaining = size - (iterator.counter.getOffset() - offset);
	if (bytesRemaining !== 0) {
		throw new Error('expected 0 bytes ' + bytesRemaining);
	}

	return {
		creationTime: toUnixTimestamp(Number(creationTime)),
		modificationTime: toUnixTimestamp(Number(modificationTime)),
		timeScale,
		durationInUnits: Number(durationInUnits),
		durationInSeconds,
		rate,
		volume,
		matrix: matrix as ThreeDMatrix,
		nextTrackId,
		type: 'mvhd-box',
		boxSize: size,
		offset,
	};
};

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Re-mux with a compliant tool: ffmpeg -i in.mp4 -c copy out.mp4 (rebuilds mvhd with correct size).
  2. Validate with MP4Box -info in.mp4 or ffprobe; both flag box-size inconsistencies.
  3. Re-fetch the source if you suspect transfer corruption.
  4. Migrate to @remotion/mediabunny (parseMedia is deprecated).

Example fix

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

// after
try {
  const r = await parseMedia({src, reader: nodeReader});
} catch (err) {
  if (err instanceof Error && /expected 0 bytes/.test(err.message)) {
    // mvhd size mismatch — re-mux to rebuild the box
  } else throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate box integrity before parsing:
//   MP4Box -info in.mp4   (flags box-size mismatches)
//   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

// mvhd size correctness is a deep binary property; not caller-type-guardable.
// => typeGuard: null

Try / catch

try {
  const {durationInSeconds} = await parseMedia({src, reader: nodeReader});
} catch (err) {
  if (err instanceof Error && /expected 0 bytes/.test(err.message)) {
    // mvhd size mismatch — re-mux to rebuild the box
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: parseMedia({src}) on an MP4/MOV whose mvhd box size is inconsistent with its version-0 or version-1 layout — e.g. trailing padding bytes, a wrong size field, or a version the parser did not fully account for. Since mvhd carries the movie timescale, this also blocks all track registration.

Common situations: Files produced by non-compliant muxers that pad boxes incorrectly; hand-edited or patched MP4s; corrupted downloads where the mvhd size field is wrong.

Related errors


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