remotion-dev/remotion · error · Error
Expected stts box in trak box
Error message
Expected stts box in trak box
What it means
Thrown by collectSamplePositionsFromTrak when a trak box has no stts (Decoding Time-to-Sample) box. stts is the table that maps each sample to its decoding timestamp delta, the basis for every timing calculation in the track. ISO/IEC 14496-12 requires it for any track that carries real samples; without it the parser cannot reconstruct timestamps.
Source
Thrown at packages/media-parser/src/containers/iso-base-media/collect-sample-positions-from-trak.ts:46
const stscBox = getStscBox(trakBox);
const stssBox = getStssBox(trakBox);
const sttsBox = getSttsBox(trakBox);
const cttsBox = getCttsBox(trakBox);
if (!stszBox) {
throw new Error('Expected stsz box in trak box');
}
if (!stcoBox) {
throw new Error('Expected stco box in trak box');
}
if (!stscBox) {
throw new Error('Expected stsc box in trak box');
}
if (!sttsBox) {
throw new Error('Expected stts box in trak box');
}
if (!timescaleAndDuration) {
throw new Error('Expected timescale and duration in trak box');
}
const samplePositions = getSamplePositions({
stcoBox,
stscBox,
stszBox,
stssBox,
sttsBox,
cttsBox,
});
return samplePositions;
};
View on GitHub (pinned to 78fe4bb3fd)
Solutions
- Re-mux with ffmpeg `-c copy -movflags faststart` to regenerate stts.
- Run `ffprobe` on the source and reject files whose streams report errors.
- Catch the error at the parse boundary and present a 'corrupt or unsupported file' message.
- If the source is a stream you control, ensure the upstream encoder writes a complete sample table.
Example fix
// before
await parseMedia({ src, fields: { samplePositions: true } });
// after
try {
await parseMedia({ src, fields: { samplePositions: true } });
} catch (err) {
if (String(err?.message).startsWith('Expected st')) {
throw new Error('MP4 sample table is incomplete. Re-mux the file with ffmpeg -movflags faststart.');
}
throw err;
} Defensive patterns
Strategy: try-catch
Validate before calling
import {execFileSync} from 'node:child_process';
function hasValidTiming(file: string): boolean {
try {
const out = execFileSync('ffprobe', ['-v', 'error', '-show_entries', 'stream=codec_type,duration', '-of', 'json', file], {encoding: 'utf8'});
const data = JSON.parse(out);
return data.streams?.every((s: any) => typeof s.duration === 'string');
} catch { return false; }
} Type guard
import type {TrakBox} from './trak/trak';
import {getSttsBox} from './traversal';
function trakHasStts(trakBox: TrakBox): boolean {
return getSttsBox(trakBox) !== null;
} Try / catch
try {
const positions = collectSamplePositionsFromTrak(trakBox);
} catch (err) {
if (/Expected stts box/i.test(String(err?.message))) {
return { seekable: false, reason: 'missing-stts' };
}
throw err;
} Prevention
- Validate uploads with ffprobe before storing them as parseable assets.
- Group all 'Expected <table> box' failures behind one user-facing error class.
- Re-mux with faststart as a normalization step so the sample tables are always rebuilt.
- Do not attempt to seek a file until its full moov has been parsed.
When it happens
Trigger: A progressive MP4 trak whose stbl lacks stts. Reachable for traks authored without a time table, or when a truncation/copy fault dropped the box. The check fires after stsz, stco, and stsc have already validated, so this is the fourth mandatory table the parser needs.
Common situations: Half-downloaded or partially uploaded MP4s. Files produced by experimental or buggy muxers. Tracks repackaged from transport streams (.ts) into MP4 incorrectly. Damaged media in a CDN cache.
Related errors
- Expected timescale and duration in trak box
- Expected timescale and duration in trak box
- Expected stsz box in trak box
- Expected stco box in trak box
- Expected stsc box in trak box
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/eff807bb1bc377d9.
Report an issue: GitHub.