{"record":{"id":"8d3f2cb8117f03b0","repo":"SubtitleEdit/subtitleedit","slug":"no-vobsub-subtitle-packs-in-subpath","errorCode":null,"errorMessage":"No VobSub subtitle packs in: {subPath}","messagePattern":"No VobSub subtitle packs in: (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/seconv/Core/BitmapSubtitleLoader.cs","lineNumber":91,"sourceCode":"    /// VobSub <c>.sub</c> (+ optional <c>.idx</c>) → bitmap events. Uses\n    /// <see cref=\"VobSubParser.OpenSubIdx\"/>, which uses the .idx for timing + palette when\n    /// present and otherwise parses the .sub's MPEG-PS stream directly (stream PTS timing +\n    /// a default palette). The frame size comes from the .idx's <c>size:</c> line when it has\n    /// one — VobSub is not always DVD-sized (Subtitle Edit's own export writes whatever the\n    /// source was, e.g. <c>size: 1920x1080</c>) and squeezing a 1920x1080 stream into a DVD\n    /// frame moves every subpicture. Without that line, fall back to the DVD standards\n    /// (720x576 PAL, 720x480 NTSC) rather than <c>--resolution</c> / 1920x1080.\n    /// </summary>\n    public static IReadOnlyList<BitmapSubtitleItem> LoadVobSub(string subPath, string idxPath, bool isPal)\n    {\n        var parser = new VobSubParser(isPal);\n        // OpenSubIdx falls back to parsing the .sub stream directly when the .idx is missing,\n        // so an absent companion is not fatal — see IsBinaryVobSub for the caller's gate.\n        parser.OpenSubIdx(subPath, idxPath);\n        var packs = parser.MergeVobSubPacks();\n        if (packs.Count == 0)\n        {\n            throw new InvalidOperationException($\"No VobSub subtitle packs in: {subPath}\");\n        }\n\n        var (screenWidth, screenHeight) = TryGetVobSubIdxScreenSize(ReadIdxText(idxPath))\n                                          ?? (720, isPal ? 576 : 480);\n\n        var items = new List<BitmapSubtitleItem>(packs.Count);\n        var skipped = 0;\n        foreach (var pack in packs)\n        {\n            // Without the .idx CLUT, SubPicture.GetBitmap skips both the SetColor and\n            // SetContrast (per-plane alpha) display commands, so normally-transparent\n            // outline/anti-alias planes render opaque and fuse into the glyphs — the\n            // garbled OCR in issue #12772 ('-'→'=', 'S'→'$'). Mirrors the GUI, which\n            // always passes VobSubParser.IdxPalette.\n            if (parser.IdxPalette.Count > 0)\n            {\n                pack.Palette = parser.IdxPalette;\n            }","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/seconv/Core/BitmapSubtitleLoader.cs#L73-L109","documentation":"InvalidOperationException from LoadVobSub: VobSubParser.OpenSubIdx ran but MergeVobSubPacks returned zero subtitle packs. The .sub file parsed (no throw) but contained no usable SPUs. The .idx is optional (OpenSubIdx falls back to stream parsing), so its absence alone is not the cause.","triggerScenarios":"Pointing LoadVobSub at a .sub that is empty, truncated, or not an MPEG-PS VobSub stream; corrupt pack headers; or a .sub that is actually another format.","commonSituations":"Copied .sub without the .idx and the stream itself has no packs; demuxer wrote a zero-byte .sub; user passed an MKV-extracted .sub that uses a different container.","solutions":["Confirm the file is an MPEG-PS VobSub .sub (look for pack start codes 0x000001BA).","Re-extract the VobSub from the source VOB/MKV (e.g. mkvextract tracks <file> <n>:out.sub).","Provide the matching .idx alongside the .sub so timing/palette load correctly."],"exampleFix":"// before\nif (packs.Count == 0)\n    throw new InvalidOperationException($\"No VobSub subtitle packs in: {subPath}\");\n\n// after\nif (packs.Count == 0)\n    throw new InvalidOperationException($\"No VobSub subtitle packs in '{subPath}'. File size: {new FileInfo(subPath).Length} bytes; idx present: {File.Exists(idxPath)}.\");","handlingStrategy":"validation","validationCode":"static bool LooksLikeVobSub(string path)\n{\n    if (!File.Exists(path)) return false;\n    using var fs = File.OpenRead(path);\n    var buf = new byte[4];\n    if (fs.Read(buf, 0, 4) != 4) return false;\n    return buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01 && (buf[3] == 0xBA || buf[3] == 0xBD);\n}","typeGuard":"static bool IsVobSubStream(string path) => LooksLikeVobSub(path);","tryCatchPattern":"null","preventionTips":["Sniff for MPEG-PS pack start codes (0x000001BA / 0x000001BD) before parsing.","Keep the .idx next to the .sub so palette/timing load cleanly."],"tags":["subtitles","vobsub","dvd","file-format","validation"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}