{"record":{"id":"69c2954340d75440","repo":"dgtlmoon/changedetection.io","slug":"command-line-tool-tool-was-not-found-in-system","errorCode":null,"errorMessage":"Command-line `{tool}` tool was not found in system PATH, was it installed?","messagePattern":"Command-line `(.+?)` tool was not found in system PATH, was it installed\\?","errorType":"exception","errorClass":"PDFToHTMLToolNotFound","httpStatus":null,"severity":"error","filePath":"changedetectionio/processors/text_json_diff/processor.py","lineNumber":297,"sourceCode":"        Supports two RSS processing modes:\n        - 'default': Inline CDATA replacement (original behavior)\n        - 'formatted': Format RSS items with title, link, guid, pubDate, and description (CDATA unmarked)\n        \"\"\"\n        from changedetectionio import rss_tools\n        rss_mode = self.datastore.data[\"settings\"][\"application\"].get(\"rss_reader_mode\")\n        if rss_mode:\n            # Format RSS items nicely with CDATA content unmarked and converted to text\n            return rss_tools.format_rss_items(content)\n        else:\n            # Default: Original inline CDATA replacement\n            return cdata_in_document_to_text(html_content=content)\n\n    def preprocess_pdf(self, raw_content):\n        \"\"\"Convert PDF to HTML using external tool.\"\"\"\n        from shutil import which\n        tool = os.getenv(\"PDF_TO_HTML_TOOL\", \"pdftohtml\")\n        if not which(tool):\n            raise PDFToHTMLToolNotFound(\n                f\"Command-line `{tool}` tool was not found in system PATH, was it installed?\"\n            )\n\n        import subprocess\n        proc = subprocess.Popen(\n            [tool, '-stdout', '-', '-s', 'out.pdf', '-i'],\n            stdout=subprocess.PIPE,\n            stdin=subprocess.PIPE\n        )\n        proc.stdin.write(raw_content)\n        proc.stdin.close()\n        html_content = proc.stdout.read().decode('utf-8')\n        proc.wait(timeout=60)\n\n        # Add metadata for change detection\n        metadata = (\n            f\"<p>Added by changedetection.io: Document checksum - \"\n            f\"{hashlib.md5(raw_content).hexdigest().upper()} \"","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/dgtlmoon/changedetection.io/blob/5d9c7c6da76340597243e8163c4f2439237fa0e8/changedetectionio/processors/text_json_diff/processor.py#L279-L315","documentation":"PDFToHTMLToolNotFound raised by preprocess_pdf in the text_json_diff processor when the external pdftohtml binary (or the name given in PDF_TO_HTML_TOOL) cannot be found via shutil.which. Watching a PDF URL requires this poppler-utils tool to be installed on the host/container.","triggerScenarios":"A watch whose content-type is PDF triggers preprocess_pdf; os.getenv('PDF_TO_HTML_TOOL', 'pdftohtml') is resolved against PATH and which() returns None because poppler-utils is not installed or the container lacks the binary.","commonSituations":"Running the changedetection.io Docker image variant without the extra tools; custom/k8s deployments missing poppler-utils; a custom tool name in PDF_TO_HTML_TOOL that is misspelled or not on PATH; alpine/slim base images.","solutions":["Install poppler-utils: apt-get install -y poppler-utils (Debian/Ubuntu) or apk add poppler-utils (Alpine)","If using a custom converter, set PDF_TO_HTML_TOOL to the full path of an existing executable","Verify with: which pdftohtml && pdftohtml -v","Rebuild your Docker image FROM the changedetectionio image that includes tools, or add the install to your Dockerfile"],"exampleFix":"# before (Dockerfile)\nFROM python:3.12-slim\nCOPY . /app\n# after\nFROM python:3.12-slim\nRUN apt-get update && apt-get install -y poppler-utils && rm -rf /var/lib/apt/lists/*\nCOPY . /app","handlingStrategy":"validation","validationCode":"import os\nfrom shutil import which\ntool = os.getenv('PDF_TO_HTML_TOOL', 'pdftohtml')\nif not which(tool):\n    raise SystemExit(f'Install poppler-utils or set PDF_TO_HTML_TOOL to a valid binary')","typeGuard":null,"tryCatchPattern":"try:\n    handler.run_changedetection(watch, ...)\nexcept PDFToHTMLToolNotFound:\n    alert_ops('pdftohtml missing on worker host')","preventionTips":["Include poppler-utils in your Dockerfile/AMI bake so the failure can't occur","Health-check the tool at startup with shutil.which and fail fast","Document PDF_TO_HTML_TOOL for custom converters, using absolute paths"],"tags":["pdf","pdftohtml","poppler","missing-dependency","docker"],"backgroundTag":"missing-system-dependency","analyzedSha":"5d9c7c6da76340597243e8163c4f2439237fa0e8","analyzedAt":"2026-08-27T19:41:16.067Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}