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
- 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).
- Validate with MP4Box -info or ffprobe; a missing/misplaced mvhd is flagged.
- Re-fetch the source if you suspect corruption.
- 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
- Re-mux files with ffmpeg to ensure mvhd precedes trak inside moov.
- Validate moov structure with MP4Box -info / ffprobe before parsing.
- Re-fetch sources suspected of corruption or hand-editing.
- Migrate to @remotion/mediabunny (parseMedia is deprecated).
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
- expected 0 bytes ${bytesRemaining}
- No moov box found
- Could not find number of channels
- Could not find sample rate
- No video sample
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/8a16d76f923d7f67.
Report an issue: GitHub.