{"record":{"id":"de1f733890b1f919","repo":"opendataloader-project/opendataloader-pdf","slug":"unknown-ocr-engine-ocr-engine-e-navailable","errorCode":null,"errorMessage":"Unknown ocr_engine '{ocr_engine}': {e}\\nAvailable engines: {available}","messagePattern":"Unknown ocr_engine '(.+?)': (.+?)\\\\nAvailable engines: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/opendataloader-pdf/src/opendataloader_pdf/hybrid_server.py","lineNumber":463,"sourceCode":"        # so enforce the denylist here too. Without this, the module-level claim\n        # that `_OCR_ENGINE_DENYLIST` is shared across CLI and create_converter\n        # would only be true at the CLI layer.\n        available = sorted(set(ocr_factory.registered_kind) - _OCR_ENGINE_DENYLIST)\n        raise ValueError(\n            f\"OCR engine '{ocr_engine}' is not supported in hybrid local mode \"\n            f\"(filtered by _OCR_ENGINE_DENYLIST). Available engines: {available}\"\n        )\n    try:\n        ocr_options = ocr_factory.create_options(\n            kind=ocr_engine,\n            force_full_page_ocr=force_full_page_ocr,\n        )\n    except RuntimeError as e:\n        # Library-friendly error type so programmatic callers can catch and retry\n        # with a different engine. main() relies on argparse `choices` to gate\n        # invalid CLI input, so this branch is reached only via direct calls.\n        available = sorted(set(ocr_factory.registered_kind) - _OCR_ENGINE_DENYLIST)\n        raise ValueError(\n            f\"Unknown ocr_engine '{ocr_engine}': {e}\\nAvailable engines: {available}\"\n        ) from e\n\n    if ocr_lang:\n        ocr_options.lang = ocr_lang\n\n    # Tesseract-only: Page Segmentation Mode\n    if psm is not None and isinstance(\n        ocr_options, (TesseractOcrOptions, TesseractCliOcrOptions)\n    ):\n        ocr_options.psm = psm\n\n    # Configure picture description options with custom prompt.\n    # When picture_description_prompt is None or blank, omit the field so\n    # docling's built-in default prompt is used. A blank string would otherwise\n    # silently produce empty-prompt output — same class of silent-flag bug\n    # as PDFDLOSP-20 reported.\n    picture_description_options = None","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/opendataloader-project/opendataloader-pdf/blob/a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8/python/opendataloader-pdf/src/opendataloader_pdf/hybrid_server.py#L445-L481","documentation":"ValueError raised when ocr_factory.create_options(kind=ocr_engine, ...) threw a RuntimeError because the engine name is genuinely unknown/unregistered to docling's factory (not merely denylisted — that is error 94). The original RuntimeError is chained (raise ... from e) and the message lists the engines that ARE available after subtracting the denylist, so the caller can pick a valid one.","triggerScenarios":"Calling create_converter with an ocr_engine that is neither denied (error 94) nor registered in docling's ocr_factory — a typo, an engine whose plugin/package is not installed, or an engine renamed in a newer docling version.","commonSituations":"Typo in the engine name ('tessaract' vs 'tesseract'). The engine's extra package was never installed so docling did not register it. A docling upgrade renamed or removed an engine. A caller uses an engine valid in a different docling version.","solutions":["Pick an engine from the 'Available engines' list in the error message.","Install the engine's extra package if it is optional (e.g. the tesseract system binary or the easyocr/torch extras) so docling registers it.","Fix typos in the engine name and match docling's registered kind exactly.","After upgrading docling, re-check registered engines: python -c \"from docling.models.factories import get_ocr_factory; print(get_ocr_factory(allow_external_plugins=False).registered_kind)\"."],"exampleFix":"# before: typo / unregistered engine\ncreate_converter(ocr_engine='tessaract')  # -> ValueError: Unknown ocr_engine\n# after: correct registered name\ncreate_converter(ocr_engine='tesseract')","handlingStrategy":"validation","validationCode":"from docling.models.factories import get_ocr_factory\nfrom opendataloader_pdf.hybrid_server import _OCR_ENGINE_DENYLIST\ndef is_known_engine(engine: str) -> bool:\n    factory = get_ocr_factory(allow_external_plugins=False)\n    return engine in (set(factory.registered_kind) - _OCR_ENGINE_DENYLIST)\n","typeGuard":"def is_unknown_engine_error(exc: ValueError) -> bool:\n    return isinstance(exc, ValueError) and \"Unknown ocr_engine\" in str(exc)","tryCatchPattern":"try:\n    create_converter(ocr_engine=engine)\nexcept ValueError as e:\n    if \"Unknown ocr_engine\" in str(e):\n        # message lists available engines; fall back to one\n        engine = \"auto\"\n        create_converter(ocr_engine=engine)\n    raise","preventionTips":["Validate the engine against docling's registered_kind minus the denylist before calling.","Install the engine's extra package so docling registers it.","After a docling upgrade, re-check registered engine names."],"tags":["hybrid","ocr","docling","config","valueerror","python"],"backgroundTag":null,"analyzedSha":"a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8","analyzedAt":"2026-08-14T05:22:03.953Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}