remotion-dev/remotion · error · Error

Expected stsc box in trak box

Error message

Expected stsc box in trak box

What it means

Thrown by collectSamplePositionsFromTrak when a trak box lacks an stsc (Sample-to-Chunk) box. The stsc table maps each chunk to the number of samples it contains plus their default size delta, which is required to translate sample indices into byte ranges. ISO/IEC 14496-12 mandates stsc inside stbl for any sample table that is actually populated.

Source

Thrown at packages/media-parser/src/containers/iso-base-media/collect-sample-positions-from-trak.ts:42

	}

	const stszBox = getStszBox(trakBox);
	const stcoBox = getStcoBox(trakBox);
	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,
	});

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Re-mux with `ffmpeg -i input.mp4 -c copy -movflags faststart fixed.mp4` to rebuild the sample tables.
  2. Validate with `ffprobe` and reject the file upstream if the sample table is incomplete.
  3. Wrap parse/seek calls in try/catch and degrade gracefully (skip seeking, treat as non-seekable stream).
  4. If you produce the files, switch muxer settings to a conformant stbl layout.

Example fix

// before
const positions = collectSamplePositionsFromTrak(trakBox);

// after
let positions;
try {
  positions = collectSamplePositionsFromTrak(trakBox);
} catch (err) {
  return { seekable: false, reason: 'incomplete-sample-table' };
}
Defensive patterns

Strategy: try-catch

Validate before calling

import {execFileSync} from 'node:child_process';
function isSampleTableComplete(file: string): boolean {
  try {
    execFileSync('ffprobe', ['-v', 'error', '-count_frames', '-select_streams', 'v:0', '-show_entries', 'stream=nb_read_frames', '-of', 'csv', file], {encoding: 'utf8'});
    return true;
  } catch { return false; }
}

Type guard

import type {TrakBox} from './trak/trak';
import {getStscBox} from './traversal';
function trakHasStsc(trakBox: TrakBox): boolean {
  return getStscBox(trakBox) !== null;
}

Try / catch

try {
  const positions = collectSamplePositionsFromTrak(trakBox);
} catch (err) {
  if (/Expected stsc box/i.test(String(err?.message))) {
    return { seekable: false, reason: 'missing-stsc' };
  }
  throw err;
}

Prevention

When it happens

Trigger: A progressive MP4 trak whose stbl has no stsc child. Common with empty/placeholder traks, severely truncated files, or non-conformant muxers. Also reachable if the traversal that fetches stsc returns null because the box is present but parsed as a different type due to a size/encoding bug.

Common situations: Truncated downloads where the moov is at the head and the stbl got cut off. Files authored by research/specialized tools that write stsz/stco but skip stsc. Damaged files that survived a copy but lost a box boundary.

Related errors


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