remotion-dev/remotion · error · Error

Movie timescale is not set

Error message

Movie timescale is not set

What it means

Thrown in processBox() while handling a trak box. movieTimeScaleState.getTrackTimescale() returned null, meaning the movie timescale (set when an mvhd box is parsed) was never established before this trak was processed. The timescale is required to convert edit-list offsets to seconds, so the parser aborts the trak.

Source

Thrown at packages/media-parser/src/containers/iso-base-media/process-box.ts:399

	if (boxType === 'trak') {
		if (!onlyIfMoovAtomExpected) {
			throw new Error('State is required');
		}

		const {tracks, onAudioTrack, onVideoTrack} = onlyIfMoovAtomExpected;

		const trakBox = await parseTrak({
			size: boxSize,
			offsetAtStart: fileOffset,
			iterator,
			logLevel,
			contentLength,
		});

		const movieTimeScale =
			onlyIfMoovAtomExpected.movieTimeScaleState.getTrackTimescale();
		if (movieTimeScale === null) {
			throw new Error('Movie timescale is not set');
		}

		const editList = findTrackStartTimeInSeconds({movieTimeScale, trakBox});
		const transformedTrack = makeBaseMediaTrack(trakBox, editList);

		if (transformedTrack && transformedTrack.type === 'video') {
			await registerVideoTrack({
				track: transformedTrack,
				container: 'mp4',
				logLevel,
				onVideoTrack,
				registerVideoSampleCallback:
					onlyIfMoovAtomExpected.registerVideoSampleCallback,
				tracks,
			});
		}

		if (transformedTrack && transformedTrack.type === 'audio') {

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Re-mux with a compliant tool to fix box ordering: ffmpeg -i in.mp4 -c copy -moov_size 0 out.mp4 (or simply ffmpeg -i in.mp4 -c copy out.mp4).
  2. Validate with MP4Box -info or ffprobe; a missing/misplaced mvhd is flagged.
  3. Re-fetch the source if you suspect corruption.
  4. Migrate to @remotion/mediabunny (parseMedia is deprecated).

Example fix

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

// after
try {
  const {tracks} = await parseMedia({src, reader: nodeReader});
} catch (err) {
  if (err instanceof Error && /Movie timescale is not set/.test(err.message)) {
    // moov has no/late mvhd; re-mux to fix box ordering
  } else throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate moov/mvhd ordering with MP4Box before parsing:
//   MP4Box -info 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

// moov box ordering is a deep structural property; not caller-type-guardable.
// => typeGuard: null

Try / catch

try {
  const {tracks} = await parseMedia({src, reader: nodeReader});
} catch (err) {
  if (err instanceof Error && /Movie timescale is not set/.test(err.message)) {
    // moov has no/late mvhd; re-mux to fix box ordering
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: parseMedia({src}) on a file whose moov box contains a trak box before (or without) an mvhd box. Per the ISO spec the mvhd should precede all trak boxes; if a trak is encountered first, or moov lacks an mvhd entirely, the timescale is still null and this fires.

Common situations: Non-compliant muxers that order trak before mvhd inside moov; moov boxes missing mvhd; reordered/edited moov atoms; corrupted moov structure.

Related errors


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