{"record":{"id":"abfcb250248311c1","repo":"ocrmypdf/OCRmyPDF","slug":"could-not-find-program-program-on-the-path","errorCode":null,"errorMessage":"Could not find program '{program}' on the PATH","messagePattern":"Could not find program '(.+?)' on the PATH","errorType":"exception","errorClass":"MissingDependencyError","httpStatus":null,"severity":"error","filePath":"src/ocrmypdf/subprocess/_version.py","lineNumber":52,"sourceCode":"    # ``ocrmypdf.subprocess.run`` affect this function. Binding ``run`` at\n    # module load time would capture the real implementation and bypass the\n    # patch.\n    from ocrmypdf import subprocess as _sp\n\n    args_prog = [program, version_arg]\n    try:\n        proc = _sp.run(\n            args_prog,\n            close_fds=True,\n            text=True,\n            stdout=PIPE,\n            stderr=STDOUT,\n            check=True,\n            env=env,\n        )\n        output: str = proc.stdout\n    except FileNotFoundError as e:\n        raise MissingDependencyError(\n            f\"Could not find program '{program}' on the PATH\"\n        ) from e\n    except CalledProcessError as e:\n        if e.returncode != 0:\n            log.exception(e)\n            raise MissingDependencyError(\n                f\"Ran program '{program}' but it exited with an error:\\n{e.output}\"\n            ) from e\n        raise MissingDependencyError(\n            f\"Could not find program '{program}' on the PATH\"\n        ) from e\n\n    # Some tools (e.g. veraPDF launched on a recent JDK) print warnings before\n    # the version line, so scan each line rather than only the start of output.\n    version = None\n    for line in output.splitlines():\n        match = re.match(regex, line.strip())\n        if match:","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/ocrmypdf/OCRmyPDF/blob/5074a0b0e109362422b768fd271ed84bf717c4ec/src/ocrmypdf/subprocess/_version.py#L34-L70","documentation":"get_version() runs `<program> --version` (or equivalent) and wraps FileNotFoundError as MissingDependencyError: the external executable is not installed or not on PATH.","triggerScenarios":"Calling get_version(program, ...) or any code path that checks a tool's version (tesseract, qpdf, ghostscript, unpaper, etc.) when the binary cannot be found via shutil.which/Popen.","commonSituations":"Missing system dependency in Docker/CI images, venv activation without the tool installed, Windows installs where the tool isn't on PATH, typos in the program name for custom plugins.","solutions":["Install the missing program (e.g. apt-get install tesseract-ocr) and verify with `tesseract --version` in the same shell/env","Ensure the binary's directory is on PATH for the Python process (check os.environ['PATH'])","In Docker/CI, add the package to the image rather than relying on the host","For plugin tools, verify the program name string is correct"],"exampleFix":"# before\nver = get_version('tesseract', regex=r'tesseract (.*)')\n# after\nimport shutil\nif not shutil.which('tesseract'):\n    raise SystemExit('install tesseract: apt-get install tesseract-ocr')\nver = get_version('tesseract', regex=r'tesseract (.*)')","handlingStrategy":"validation","validationCode":"import shutil\\nif not shutil.which(program):\\n    raise SystemExit(f'{program} not installed or not on PATH')","typeGuard":null,"tryCatchPattern":"try:\\n    v = get_version(program, regex=...)\\nexcept MissingDependencyError as e:\\n    raise RuntimeError(f'install {program}: {e}') from e","preventionTips":["Check shutil.which for external tools at app startup","Install all OCRmyPDF system deps in Docker/CI images explicitly","Verify PATH inside the Python process, not just your shell"],"tags":["dependency","path","external-tool","installation"],"backgroundTag":"executable-not-on-path","analyzedSha":"5074a0b0e109362422b768fd271ed84bf717c4ec","analyzedAt":"2026-08-27T11:57:38.523Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}