remotion-dev/remotion · error · Error

No trak box found

Error message

No trak box found

What it means

Thrown by getSeekingByteFromFragmentedMp4 when getTrakBoxByTrackId(moov, firstTrack.trackId) returns null. The moov atom parsed fine and a track was registered with a given trackId, but no trak inside moov has a matching tkhd.trackId. This indicates a mismatch between the track objects the parser exposes and the actual trak boxes in the moov — typically a state inconsistency or a moov that was replaced between parse and seek.

Source

Thrown at packages/media-parser/src/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.ts:68

	if (!firstTrack) {
		throw new Error('no video and no audio tracks');
	}

	const moov = getMoovBoxFromState({
		structureState: structure,
		isoState,
		mp4HeaderSegment,
		mayUsePrecomputed: true,
	});
	if (!moov) {
		throw new Error('No moov atom found');
	}

	const trakBox = getTrakBoxByTrackId(moov, firstTrack.trackId);

	if (!trakBox) {
		throw new Error('No trak box found');
	}

	const tkhdBox = getTkhdBox(trakBox);
	if (!tkhdBox) {
		throw new Error('Expected tkhd box in trak box');
	}

	const isComplete = areSamplesComplete({
		moofBoxes: info.moofBoxes,
		tfraBoxes: info.tfraBoxes,
	});

	const {samplePositions: samplePositionsArray} =
		collectSamplePositionsFromMoofBoxes({
			moofBoxes: info.moofBoxes,
			tkhdBox,
			isComplete,
			trexBoxes: getTrexBoxes(moov),

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Reset/rebuild the tracks array whenever the moov is reloaded (e.g. on HLS variant switch).
  2. Validate that every track.trackId corresponds to a trak in the current moov before seeking.
  3. If the source is adaptive, pin to a single variant during a seek operation.
  4. Ensure tkhd.trackId is parsed correctly; if 0 or NaN, treat the file as corrupt.

Example fix

// before
await parser.seek(time);

// after
const trakIds = new Set(getTraks(moov).map((t) => getTkhdBox(t)?.trackId));
if (!tracks.every((t) => trakIds.has(t.trackId))) {
  // moov changed under us; rebuild tracks before seeking
  await reloadTracks();
}
await parser.seek(time);
Defensive patterns

Strategy: validation

Validate before calling

import type {MoovBox} from './moov/moov';
import {getTraks, getTkhdBox} from './traversal';
function moovHasTrackId(moov: MoovBox, trackId: number): boolean {
  return getTraks(moov).some((t) => getTkhdBox(t)?.trackId === trackId);
}

Type guard

import type {MoovBox} from './moov/moov';
import {getTraks, getTkhdBox} from './traversal';
function moovHasTrakForTrack(moov: MoovBox, trackId: number): boolean {
  return getTraks(moov).some((t) => getTkhdBox(t)?.trackId === trackId);
}

Try / catch

try {
  await parser.seek(time);
} catch (err) {
  if (/No trak box found/i.test(String(err?.message))) {
    // moov changed under us; rebuild tracks then retry
    await reloadTracksFromCurrentMoov();
    return parser.seek(time);
  }
  throw err;
}

Prevention

When it happens

Trigger: A track object in state.tracks carries a trackId that does not correspond to any trak in the current moov (e.g. moov was re-fetched or swapped, e.g. across HLS variant switches). Also reachable if trackId is 0 or unset because tkhd was malformed during track construction.

Common situations: Adaptive streaming where the active variant's moov changed but the track list still references the old trackId. Damaged moov where tkhd.trackId was misread. Custom readerInterface returning different bytes for the same range across calls. Race during variant switch.

Related errors


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