nilaoda/N_m3u8DL-RE · error · Exception

A required box is missing

Error message

A required box is missing

What it means

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".

Solutions

  1. Verify the segment URL returns actual MP4 fragment bytes (check magic 'styp'/'moof' boxes), not HTML or an empty body.
  2. Check the HTTP response status/content-type for the segment request and handle non-200 before parsing.
  3. Re-download or retry the segment; ensure the playlist (m3u8) is current.
  4. Confirm the stream is genuinely an fMP4 WebVTT (wvtt) segment via INIT mp4 and codec info.
Defensive patterns

Strategy: validation

Validate before calling

// reject non-MP4 payloads before parsing
static bool LooksLikeFmp4(byte[] b) => b.Length > 12 &&
    (System.Text.Encoding.ASCII.GetString(b, 4, 4) is "styp" or "moof" or "ftyp");
if (!LooksLikeFmp4(dataSeg)) throw new InvalidDataException("segment is not an fMP4 fragment");

Try / catch

try { var subs = MP4VttUtil.ExtractSub(dataSeg, baseTime); }
catch (Exception ex) when (ex.Message == "A required box is missing") {
    logger.Error($"Segment from {segmentUrl} is not a valid fMP4 fragment (first bytes: {head})");
    throw new SegmentFetchException(segmentUrl, inner: ex);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of nilaoda/N_m3u8DL-RE@e113dee70c (2026-09-13). Data as JSON: /api/errors/5f3410075f445b98. Report an issue: GitHub.

Appendix: source

Thrown at src/N_m3u8DL-RE.Parser/Mp4/MP4VttUtil.cs:93

                    sawTRUN = true;
                    if (box.Version == 1000)
                        throw new Exception("A TRUN box should have a valid version value");
                    if (box.Flags == 1000)
                        throw new Exception("A TRUN box should have a valid flags value");
                    presentations = MP4Parser.ParseTRUN(box.Reader, box.Version, box.Flags).SampleData;
                })
                .Box("mdat", MP4Parser.AllData(data =>
                {
                    if (sawMDAT)
                        throw new Exception("VTT cues in mp4 with multiple MDAT are not currently supported");
                    sawMDAT = true;
                    rawPayload = data;
                }))
                .Parse(dataSeg,/* partialOkay= */ false);

            if (!sawMDAT && !sawTFDT && !sawTRUN)
            {
                throw new Exception("A required box is missing");
            }

            var currentTime = baseTime;
            var reader = new BinaryReader2(new MemoryStream(rawPayload!));

            foreach (var presentation in presentations)
            {
                var duration = presentation.SampleDuration == 0 ? defaultDuration : presentation.SampleDuration;
                var startTime = presentation.SampleCompositionTimeOffset != 0 ?
                    baseTime + presentation.SampleCompositionTimeOffset :
                    currentTime;
                currentTime = startTime + duration;
                var totalSize = 0;
                do
                {
                    // Read the payload size.
                    var payloadSize = (int)reader.ReadUInt32();
                    totalSize += payloadSize;

View on GitHub (pinned to e113dee70c)