nilaoda/N_m3u8DL-RE · error · Exception

PSSH version can only be 0 or 1

Error message

PSSH version can only be 0 or 1

What it means

While walking the MP4 init segment, the MP4Parser FullBox handler for 'pssh' rejects PSSH boxes whose version is not 0 or 1; only these versions are defined for the Protection System Specific Header box. Any other version byte means a corrupt or nonstandard file.

Solutions

  1. Re-obtain or re-download the init segment — the file is likely corrupt.
  2. Inspect the pssh box with a tool (e.g. Bento4/MP4Box dump) to verify version and contents.
  3. Remux/repackage the content with a standard muxer (ffmpeg/Bento4) so pssh boxes use version 0 or 1.
  4. Catch the exception and skip DRM info extraction rather than aborting if PSSH is not required.

Example fix

// before
var info = MP4InitUtil.ReadInit(File.ReadAllBytes(initSegment));

// after
try
{
    var info = MP4InitUtil.ReadInit(File.ReadAllBytes(initSegment));
}
catch (Exception ex) when (ex.Message.Contains("PSSH version"))
{
    Log.Warning("Init segment has malformed pssh box; skipping DRM info");
}
Defensive patterns

Strategy: try-catch

Try / catch

try { var info = MP4InitUtil.ReadInit(bytes); }
catch (Exception ex) when (ex.Message.Contains("PSSH version"))
{ Log.Warning("Malformed pssh box; skipping DRM info"); }

Prevention

When it happens

Trigger: Calling MP4InitUtil.ReadInit on an MP4 init segment whose moov contains a pssh full box with version other than 0 or 1 (corrupt box, wrong offset parsing, or a nonstandard muxer output).

Common situations: Corrupt/truncated DASH or fMP4 init segment, an unusual muxer writing malformed pssh boxes, or feeding a non-fMP4 file into ReadInit.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at src/N_m3u8DL-RE.Parser/Mp4/MP4InitUtil.cs:33

        private static readonly byte[] SYSTEM_ID_WIDEVINE = [0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED];
        private static readonly byte[] SYSTEM_ID_PLAYREADY = [0x9A, 0x04, 0xF0, 0x79, 0x98, 0x40, 0x42, 0x86, 0xAB, 0x92, 0xE6, 0x5B, 0xE0, 0x88, 0x5F, 0x95];

        public static ParsedMP4Info ReadInit(byte[] data)
        {
            var info = new ParsedMP4Info();

            // parse init
            new MP4Parser()
                .Box("moov", MP4Parser.Children)
                .Box("trak", MP4Parser.Children)
                .Box("mdia", MP4Parser.Children)
                .Box("minf", MP4Parser.Children)
                .Box("stbl", MP4Parser.Children)
                .FullBox("stsd", MP4Parser.SampleDescription)
                .FullBox("pssh", box =>
                {
                    if (box.Version is not (0 or 1))
                        throw new Exception("PSSH version can only be 0 or 1");
                    var systemId = box.Reader.ReadBytes(16);
                    if (!SYSTEM_ID_WIDEVINE.SequenceEqual(systemId)) return;
                    
                    var dataSize = box.Reader.ReadUInt32();
                    var psshData = box.Reader.ReadBytes((int)dataSize);
                    info.PSSH = Convert.ToBase64String(psshData);
                    if (info.KID != "00000000000000000000000000000000") return;
                    
                    info.KID = HexUtil.BytesToHex(psshData[2..18]).ToLower();
                    info.isMultiDRM = true;
                })
                .FullBox("encv", MP4Parser.AllData(data => ReadBox(data, info)))
                .FullBox("enca", MP4Parser.AllData(data => ReadBox(data, info)))
                .FullBox("enct", MP4Parser.AllData(data => ReadBox(data, info)))
                .FullBox("encs", MP4Parser.AllData(data => ReadBox(data, info)))
                .Parse(data, stopOnPartial: true);

            return info;

View on GitHub (pinned to e113dee70c)