{"record":{"id":"eff807bb1bc377d9","repo":"remotion-dev/remotion","slug":"expected-stts-box-in-trak-box","errorCode":null,"errorMessage":"Expected stts box in trak box","messagePattern":"Expected stts box in trak box","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media-parser/src/containers/iso-base-media/collect-sample-positions-from-trak.ts","lineNumber":46,"sourceCode":"\tconst stscBox = getStscBox(trakBox);\n\tconst stssBox = getStssBox(trakBox);\n\tconst sttsBox = getSttsBox(trakBox);\n\tconst cttsBox = getCttsBox(trakBox);\n\n\tif (!stszBox) {\n\t\tthrow new Error('Expected stsz box in trak box');\n\t}\n\n\tif (!stcoBox) {\n\t\tthrow new Error('Expected stco box in trak box');\n\t}\n\n\tif (!stscBox) {\n\t\tthrow new Error('Expected stsc box in trak box');\n\t}\n\n\tif (!sttsBox) {\n\t\tthrow new Error('Expected stts box in trak box');\n\t}\n\n\tif (!timescaleAndDuration) {\n\t\tthrow new Error('Expected timescale and duration in trak box');\n\t}\n\n\tconst samplePositions = getSamplePositions({\n\t\tstcoBox,\n\t\tstscBox,\n\t\tstszBox,\n\t\tstssBox,\n\t\tsttsBox,\n\t\tcttsBox,\n\t});\n\n\treturn samplePositions;\n};\n","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-parser/src/containers/iso-base-media/collect-sample-positions-from-trak.ts#L28-L64","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait parseMedia({ src, fields: { samplePositions: true } });\n\n// after\ntry {\n  await parseMedia({ src, fields: { samplePositions: true } });\n} catch (err) {\n  if (String(err?.message).startsWith('Expected st')) {\n    throw new Error('MP4 sample table is incomplete. Re-mux the file with ffmpeg -movflags faststart.');\n  }\n  throw err;\n}","handlingStrategy":"try-catch","validationCode":"import {execFileSync} from 'node:child_process';\nfunction hasValidTiming(file: string): boolean {\n  try {\n    const out = execFileSync('ffprobe', ['-v', 'error', '-show_entries', 'stream=codec_type,duration', '-of', 'json', file], {encoding: 'utf8'});\n    const data = JSON.parse(out);\n    return data.streams?.every((s: any) => typeof s.duration === 'string');\n  } catch { return false; }\n}","typeGuard":"import type {TrakBox} from './trak/trak';\nimport {getSttsBox} from './traversal';\nfunction trakHasStts(trakBox: TrakBox): boolean {\n  return getSttsBox(trakBox) !== null;\n}","tryCatchPattern":"try {\n  const positions = collectSamplePositionsFromTrak(trakBox);\n} catch (err) {\n  if (/Expected stts box/i.test(String(err?.message))) {\n    return { seekable: false, reason: 'missing-stts' };\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["mp4","isobmff","media-parser","corrupt-file","timing"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}