SubtitleEdit/subtitleedit · error · InvalidOperationException

VobSub '.idx' input has no companion '.sub' ({Path.GetFileNa

Error message

VobSub '.idx' input has no companion '.sub' ({Path.GetFileName(subPath)}) — the .idx only holds timing and palette; the subtitle images live in the .sub.

What it means

Thrown by ContainerSubtitleLoader when the input file has a .idx extension but no companion .sub exists beside it (Path.ChangeExtension to .sub yields a non-existent file). A VobSub .idx only holds timing and palette metadata; the actual subtitle images live in the .sub, so the conversion cannot proceed without it. The redirect from .idx to .sub preserves the 5.0.0 behaviour documented against issue #12772.

Source

Thrown at src/seconv/Core/ContainerSubtitleLoader.cs:112

            {
                AnsiConsole.MarkupLine(
                    $"[yellow]Note: VobSub '.sub' has no '.idx' companion ({Path.GetFileName(idxPath).EscapeMarkup()}); "
                    + "reading timing from the stream and using a default color palette.[/]");
                return LoadVobSub(filePath, idxPath, options);
            }

            return null;
        }

        if (ext == ".idx")
        {
            // 5.0.0 accepted the .idx of a VobSub pair as the input file; keep that working
            // by redirecting to the companion .sub (which holds the actual subpictures) and
            // using the given .idx for timing + palette (issue #12772).
            var subPath = Path.ChangeExtension(filePath, ".sub");
            if (!File.Exists(subPath))
            {
                throw new InvalidOperationException(
                    $"VobSub '.idx' input has no companion '.sub' ({Path.GetFileName(subPath)}) — "
                    + "the .idx only holds timing and palette; the subtitle images live in the .sub.");
            }

            return LoadVobSub(subPath, filePath, options);
        }

        if (ext is ".ts" or ".m2ts" or ".mts")
        {
            return LoadTransportStream(filePath, options);
        }

        if (ext == ".mxf")
        {
            return LoadMxf(filePath, options);
        }

        return null;

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Locate the matching .sub file and place it next to the .idx with the same basename.
  2. Pass the .sub path directly instead of the .idx (the loader pairs them automatically when both exist).
  3. On case-sensitive filesystems, ensure the .sub extension matches exactly, or rename to lowercase .sub.

Example fix

// before: only movie.idx present
seconv movie.idx -o out.srt

// after: provide the companion .sub
seconv movie.sub -o out.srt   # .idx is auto-detected beside it
Defensive patterns

Strategy: validation

Validate before calling

// Validate the .idx/.sub pair exists before invoking the loader.
if (Path.GetExtension(filePath).Equals(".idx", StringComparison.OrdinalIgnoreCase))
{
    var subPath = Path.ChangeExtension(filePath, ".sub");
    if (!File.Exists(subPath))
        return Error($"Missing companion .sub next to {filePath}");
}

Try / catch

try { return ContainerSubtitleLoader.TryLoadTracks(filePath, options); }
catch (InvalidOperationException ex) when (ex.Message.Contains("companion '.sub"))
{ Console.Error.WriteLine(ex.Message); return null; }

Prevention

When it happens

Trigger: Invoking TryLoadTracks(filePath, options) (or the CLI) with a path ending in .idx where the sibling .sub (same basename, same directory) is absent — File.Exists(subPath) at line 110 returns false.

Common situations: User selects only the .idx of a VobSub pair; the .sub was deleted or never copied alongside; case-sensitivity on Linux where the file is .SUB but ChangeExtension produces .sub; pointing the tool at a lone .idx downloaded without its pair.

Related errors


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/7d392fa7f1fda1ae. Report an issue: GitHub.