opendataloader-project/opendataloader-pdf · error · ValueError

OCR engine '{ocr_engine}' is not supported in hybrid local m

Error message

OCR engine '{ocr_engine}' is not supported in hybrid local mode (filtered by _OCR_ENGINE_DENYLIST). Available engines: {available}

What it means

ValueError raised when the requested ocr_engine is in the module-level _OCR_ENGINE_DENYLIST (currently frozenset({'kserve_v2_ocr'})), which blocks remote-inference-server OCR engines in hybrid local mode for security and reproducibility. This guard is enforced in create_converter too, not just the CLI argparse choices, because programmatic callers bypass argparse. The message lists the engines that remain available (registered kinds minus the denylist).

Source

Thrown at python/opendataloader-pdf/src/opendataloader_pdf/hybrid_server.py:449

        TableFormerMode,
        TableStructureOptions,
        TesseractCliOcrOptions,
        TesseractOcrOptions,
    )
    from docling.document_converter import DocumentConverter, PdfFormatOption
    from docling.models.factories import get_ocr_factory

    # Delegate engine selection to docling's factory. We block external plugins for
    # security/reproducibility; the module-level _OCR_ENGINE_DENYLIST filters
    # engines unsuitable for hybrid local mode (e.g., remote inference servers).
    ocr_factory = get_ocr_factory(allow_external_plugins=False)
    if ocr_engine in _OCR_ENGINE_DENYLIST:
        # Programmatic callers (importing this module) bypass argparse `choices`,
        # so enforce the denylist here too. Without this, the module-level claim
        # that `_OCR_ENGINE_DENYLIST` is shared across CLI and create_converter
        # would only be true at the CLI layer.
        available = sorted(set(ocr_factory.registered_kind) - _OCR_ENGINE_DENYLIST)
        raise ValueError(
            f"OCR engine '{ocr_engine}' is not supported in hybrid local mode "
            f"(filtered by _OCR_ENGINE_DENYLIST). Available engines: {available}"
        )
    try:
        ocr_options = ocr_factory.create_options(
            kind=ocr_engine,
            force_full_page_ocr=force_full_page_ocr,
        )
    except RuntimeError as e:
        # Library-friendly error type so programmatic callers can catch and retry
        # with a different engine. main() relies on argparse `choices` to gate
        # invalid CLI input, so this branch is reached only via direct calls.
        available = sorted(set(ocr_factory.registered_kind) - _OCR_ENGINE_DENYLIST)
        raise ValueError(
            f"Unknown ocr_engine '{ocr_engine}': {e}\nAvailable engines: {available}"
        ) from e

    if ocr_lang:

View on GitHub (pinned to a7789b8e77)

Solutions

  1. Switch to an allowed engine: use one of the values printed in the 'Available engines' list (e.g. easyocr, tesseract, or auto).
  2. If you genuinely need remote inference, do NOT use hybrid local mode — run the engine as a separate service and adjust your architecture, since the denylist is intentional for local mode.
  3. Update any persisted config/defaults that reference a denied engine name.
  4. Check the current denylist via from opendataloader_pdf.hybrid_server import _OCR_ENGINE_DENYLIST before choosing an engine programmatically.

Example fix

# before: denied remote-inference engine in local mode
create_converter(ocr_engine='kserve_v2_ocr')  # -> ValueError
# after: use a locally-available engine
create_converter(ocr_engine='easyocr')
Defensive patterns

Strategy: validation

Validate before calling

from opendataloader_pdf.hybrid_server import _OCR_ENGINE_DENYLIST
def is_allowed_engine(engine: str) -> bool:
    return engine not in _OCR_ENGINE_DENYLIST

Type guard

def is_denied_engine_error(exc: ValueError) -> bool:
    return isinstance(exc, ValueError) and "_OCR_ENGINE_DENYLIST" in str(exc)

Try / catch

try:
    create_converter(ocr_engine=engine)
except ValueError as e:
    if "_OCR_ENGINE_DENYLIST" in str(e):
        # pick a locally-available engine instead
        engine = "easyocr"
        create_converter(ocr_engine=engine)
    raise

Prevention

When it happens

Trigger: Calling create_converter (or the hybrid server path) with ocr_engine='kserve_v2_ocr' (or any future value added to _OCR_ENGINE_DENYLIST). Programmatic import-and-call bypasses the CLI's argparse choices validation, so this in-function check is what catches it.

Common situations: A caller copies an engine name from docling docs that includes a remote inference server engine blocked here. A config defaults to a denied engine. An upgrade added a new engine to the denylist that the caller's saved config still references.

Related errors


AI-assisted analysis of opendataloader-project/opendataloader-pdf@a7789b8e77 (2026-08-14). Data as JSON: /api/errors/e9387cfe330bec2a. Report an issue: GitHub.