{"record":{"id":"5f3410075f445b98","repo":"nilaoda/N_m3u8DL-RE","slug":"a-required-box-is-missing","errorCode":null,"errorMessage":"A required box is missing","messagePattern":"A required box is missing","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/N_m3u8DL-RE.Parser/Mp4/MP4VttUtil.cs","lineNumber":93,"sourceCode":"                    sawTRUN = true;\n                    if (box.Version == 1000)\n                        throw new Exception(\"A TRUN box should have a valid version value\");\n                    if (box.Flags == 1000)\n                        throw new Exception(\"A TRUN box should have a valid flags value\");\n                    presentations = MP4Parser.ParseTRUN(box.Reader, box.Version, box.Flags).SampleData;\n                })\n                .Box(\"mdat\", MP4Parser.AllData(data =>\n                {\n                    if (sawMDAT)\n                        throw new Exception(\"VTT cues in mp4 with multiple MDAT are not currently supported\");\n                    sawMDAT = true;\n                    rawPayload = data;\n                }))\n                .Parse(dataSeg,/* partialOkay= */ false);\n\n            if (!sawMDAT && !sawTFDT && !sawTRUN)\n            {\n                throw new Exception(\"A required box is missing\");\n            }\n\n            var currentTime = baseTime;\n            var reader = new BinaryReader2(new MemoryStream(rawPayload!));\n\n            foreach (var presentation in presentations)\n            {\n                var duration = presentation.SampleDuration == 0 ? defaultDuration : presentation.SampleDuration;\n                var startTime = presentation.SampleCompositionTimeOffset != 0 ?\n                    baseTime + presentation.SampleCompositionTimeOffset :\n                    currentTime;\n                currentTime = startTime + duration;\n                var totalSize = 0;\n                do\n                {\n                    // Read the payload size.\n                    var payloadSize = (int)reader.ReadUInt32();\n                    totalSize += payloadSize;","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/nilaoda/N_m3u8DL-RE/blob/e113dee70c924ee08dae5460624909b04d84cb76/src/N_m3u8DL-RE.Parser/Mp4/MP4VttUtil.cs#L75-L111","documentation":"After parsing the segment, ExtractSub verifies it saw at least one of the required boxes: 'mdat' (cue payload), 'tfdt' (base media decode time), or 'trun' (sample runs). If none were present, the data is not a valid fragmented MP4 WVTT segment, so it throws \"A required box is missing\".","triggerScenarios":"ExtractSub is called with a dataSeg that is not an MP4 fragment at all (wrong content type, HTML error page, empty/truncated bytes) so no mdat/tfdt/trun boxes parse.","commonSituations":"Playlist points to a wrong or moved segment URL; server returns an error page with 200 status; content mistakenly treated as fMP4 when it is actually a different container; zero-byte segments from a failed mirror.","solutions":["Verify the segment URL returns actual MP4 fragment bytes (check magic 'styp'/'moof' boxes), not HTML or an empty body.","Check the HTTP response status/content-type for the segment request and handle non-200 before parsing.","Re-download or retry the segment; ensure the playlist (m3u8) is current.","Confirm the stream is genuinely an fMP4 WebVTT (wvtt) segment via INIT mp4 and codec info."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// reject non-MP4 payloads before parsing\nstatic bool LooksLikeFmp4(byte[] b) => b.Length > 12 &&\n    (System.Text.Encoding.ASCII.GetString(b, 4, 4) is \"styp\" or \"moof\" or \"ftyp\");\nif (!LooksLikeFmp4(dataSeg)) throw new InvalidDataException(\"segment is not an fMP4 fragment\");","typeGuard":null,"tryCatchPattern":"try { var subs = MP4VttUtil.ExtractSub(dataSeg, baseTime); }\ncatch (Exception ex) when (ex.Message == \"A required box is missing\") {\n    logger.Error($\"Segment from {segmentUrl} is not a valid fMP4 fragment (first bytes: {head})\");\n    throw new SegmentFetchException(segmentUrl, inner: ex);\n}","preventionTips":["Check HTTP status and content-type before parsing segments.","Verify the first box type bytes are styp/moof/ftyp.","Keep playlists fresh; tokenized segment URLs expire.","Handle servers returning HTML with 200 status."],"tags":["mp4","malformed-input","subtitles"],"backgroundTag":"unexpected-response-shape","analyzedSha":"e113dee70c924ee08dae5460624909b04d84cb76","analyzedAt":"2026-09-13T02:43:21.078Z","contentChangedAt":"2026-09-13T02:43:21.078Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}