{"record":{"id":"5358c2d12c37b44c","repo":"remotion-dev/remotion","slug":"expected-timescale-and-duration-in-trak-box-5358c2","errorCode":null,"errorMessage":"Expected timescale and duration in trak box","messagePattern":"Expected timescale and duration in trak box","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/media-parser/src/containers/iso-base-media/make-track.ts","lineNumber":58,"sourceCode":"export const makeBaseMediaTrack = (\n\ttrakBox: TrakBox,\n\tstartTimeInSeconds: number,\n):\n\t| MediaParserVideoTrack\n\t| MediaParserAudioTrack\n\t| MediaParserOtherTrack\n\t| null => {\n\tconst tkhdBox = getTkhdBox(trakBox);\n\n\tconst videoDescriptors = getVideoDescriptors(trakBox);\n\tconst timescaleAndDuration = getTimescaleAndDuration(trakBox);\n\n\tif (!tkhdBox) {\n\t\tthrow new Error('Expected tkhd 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\tif (trakBoxContainsAudio(trakBox)) {\n\t\tconst numberOfChannels = getNumberOfChannelsFromTrak(trakBox);\n\t\tif (numberOfChannels === null) {\n\t\t\tthrow new Error('Could not find number of channels');\n\t\t}\n\n\t\tconst sampleRate = getSampleRate(trakBox);\n\t\tif (sampleRate === null) {\n\t\t\tthrow new Error('Could not find sample rate');\n\t\t}\n\n\t\tconst {codecString, description} = getAudioCodecStringFromTrak(trakBox);\n\t\tconst codecPrivate =\n\t\t\tgetCodecPrivateFromTrak(trakBox) ?? description ?? null;\n\t\tconst codecEnum = getAudioCodecFromTrack(trakBox);\n","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/media-parser/src/containers/iso-base-media/make-track.ts#L40-L76","documentation":"Thrown by makeBaseMediaTrack when getTimescaleAndDuration(trakBox) returns null during track construction. That helper reads mdhd (Media Header) for timescale and duration; null means mdhd is missing or unparseable, so the track has no time base. Without timescale the parser cannot convert sample timestamps to seconds and refuses to build the track.","triggerScenarios":"Reached for every trak during track construction. Fires when mdhd is absent from the mdia subtree, or when mdhd was misparsed (wrong version/flags) so getTimescaleAndDuration returns null. Distinct from the sample-positions version because it blocks all track creation, not just seeking.","commonSituations":"Corrupt moov where mdia is incomplete. Files from non-conformant encoders. Truncated downloads where the moov tail is cut. Muxers that emit trak without mdhd (spec violation).","solutions":["Re-mux with ffmpeg `-c copy -movflags faststart` to rebuild mdhd and the mdia subtree.","Validate with `ffprobe -show_streams -show_entries stream=time_base` and reject files with no time base.","Catch the error at the parse boundary and surface a 'corrupt file' message.","If authoring files, ensure every trak's mdia contains an mdhd box."],"exampleFix":"// before\nawait parseMedia({ src: file });\n\n// after\ntry {\n  await parseMedia({ src: file });\n} catch (err) {\n  if (/timescale and duration/i.test(String(err?.message))) {\n    throw new Error('MP4 track is missing timing info (mdhd). The file is corrupt; re-mux it with ffmpeg.');\n  }\n  throw err;\n}","handlingStrategy":"try-catch","validationCode":"import {execFileSync} from 'node:child_process';\nfunction trackHasTiming(file: string): boolean {\n  try {\n    const out = execFileSync('ffprobe', ['-v', 'error', '-show_entries', 'stream=time_base', '-of', 'json', file], {encoding: 'utf8'});\n    const data = JSON.parse(out);\n    return data.streams?.every((s: any) => !!s.time_base && s.time_base !== '0/0');\n  } catch { return false; }\n}","typeGuard":"import type {TrakBox} from './trak/trak';\nimport {getTimescaleAndDuration} from '../../get-fps';\nfunction trakHasTiming(trakBox: TrakBox): boolean {\n  return getTimescaleAndDuration(trakBox) !== null;\n}","tryCatchPattern":"try {\n  await parseMedia({ src: file });\n} catch (err) {\n  if (/timescale and duration/i.test(String(err?.message))) {\n    throw new Error('MP4 track is missing timing info (mdhd). The file is corrupt; re-mux with ffmpeg -movflags faststart.');\n  }\n  throw err;\n}","preventionTips":["Reject uploads whose ffprobe time_base is missing or zero.","Re-mux user content with faststart as a normalization step.","Catch mdhd/timescale errors centrally and emit a single 'corrupt file' message.","Ensure programmatic trak authors always include an mdhd inside mdia."],"tags":["mp4","isobmff","media-parser","trak","mdhd","timing","corrupt-file","track-construction"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}