SubtitleEdit/subtitleedit · error · InvalidOperationException

{engineName} engine requires --ocr-db=<path-to-Latin{require

Error message

{engineName} engine requires --ocr-db=<path-to-Latin{requiredExtension}> (or another {requiredExtension} file). Find them in `%AppData%\Subtitle Edit\OCR\` or download from the SE UI.

What it means

Thrown by OcrEngineFactory.ResolveOcrDbPath when the nocr or binaryocr engine is selected but `--ocr-db` is null/empty/whitespace. These two engines are template-based and have no bundled data, so a database path is mandatory — unlike tesseract (which locates tessdata) or ollama/paddle (external services).

Source

Thrown at src/seconv/Core/OcrEngineFactory.cs:31

        return engine switch
        {
            "tesseract" or "" => TesseractOcrEngine.Create(options.OcrLanguage),
            "nocr" => new NOcrOcrEngine(ResolveOcrDbPath(options, "nocr", ".nocr")),
            "binaryocr" or "binary" => new BinaryOcrOcrEngine(ResolveOcrDbPath(options, "binaryocr", ".db")),
            "ollama" => new OllamaOcrEngine(options.OllamaUrl, options.OllamaModel, options.OcrLanguage),
            "llamacpp" or "llama.cpp" or "llama" => LlamaCppOcrEngine.Create(options),
            "paddle" or "paddleocr" => PaddleOcrEngine.Create(options.OcrLanguage),
            _ => throw new InvalidOperationException(
                $"OCR engine '{options.OcrEngine}' is not supported. Use one of: tesseract, nocr, binaryocr, ollama, llamacpp, paddle.")
        };
    }

    private static string ResolveOcrDbPath(ConversionOptions options, string engineName, string requiredExtension)
    {
        if (string.IsNullOrWhiteSpace(options.OcrDb))
        {
            var displayExt = requiredExtension.TrimStart('.');
            throw new InvalidOperationException(
                $"{engineName} engine requires --ocr-db=<path-to-Latin{requiredExtension}> (or another {requiredExtension} file). " +
                $"Find them in `%AppData%\\Subtitle Edit\\OCR\\` or download from the SE UI.");
        }
        var path = options.OcrDb;
        if (!path.EndsWith(requiredExtension, StringComparison.OrdinalIgnoreCase))
        {
            path += requiredExtension;
        }
        return path;
    }
}

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Add `--ocr-db=<path-to-Latin.nocr>` for nocr or `--ocr-db=<path-to-Latin.db>` for binaryocr.
  2. Locate the db under `%AppData%\Subtitle Edit\OCR\` (Windows) or copy it from a SE install.
  3. Switch to tesseract if you have no .nocr/.db file and just need text OCR.

Example fix

// before
seconv in.sup out.srt --ocr-engine binaryocr
// after
seconv in.sup out.srt --ocr-engine binaryocr --ocr-db=/opt/SE/OCR/Latin.db
Defensive patterns

Strategy: validation

Validate before calling

if ((options.OcrEngine is "nocr" or "binaryocr" or "binary") && string.IsNullOrWhiteSpace(options.OcrDb))
    throw new ArgumentException("--ocr-db is required for " + options.OcrEngine);

Type guard

static bool EngineNeedsDb(string? e) =>
    e is "nocr" or "binaryocr" or "binary";
static bool IsDbOptionSatisfied(ConversionOptions o) =>
    !EngineNeedsDb(o.OcrEngine) || !string.IsNullOrWhiteSpace(o.OcrDb);

Try / catch

try { var engine = OcrEngineFactory.Create(options); }
catch (InvalidOperationException ex) when (ex.Message.Contains("requires --ocr-db"))
{
    // prompt for db path, re-run
}

Prevention

When it happens

Trigger: Calling `OcrEngineFactory.Create` with `OcrEngine` = 'nocr' or 'binaryocr'/'binary' while `options.OcrDb` is unset. The factory routes these to ResolveOcrDbPath, which throws before the engine constructor runs.

Common situations: Assuming nocr/binaryocr work out of the box like tesseract; migrating a script from tesseract to nocr without adding --ocr-db; the GUI installed the db but the user did not copy the path into the CLI invocation.

Related errors


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