dgtlmoon/changedetection.io · error · PDFToHTMLToolNotFound
Command-line `{tool}` tool was not found in system PATH, was
Error message
Command-line `{tool}` tool was not found in system PATH, was it installed? What it means
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.
Source
Thrown at changedetectionio/processors/text_json_diff/processor.py:297
Supports two RSS processing modes:
- 'default': Inline CDATA replacement (original behavior)
- 'formatted': Format RSS items with title, link, guid, pubDate, and description (CDATA unmarked)
"""
from changedetectionio import rss_tools
rss_mode = self.datastore.data["settings"]["application"].get("rss_reader_mode")
if rss_mode:
# Format RSS items nicely with CDATA content unmarked and converted to text
return rss_tools.format_rss_items(content)
else:
# Default: Original inline CDATA replacement
return cdata_in_document_to_text(html_content=content)
def preprocess_pdf(self, raw_content):
"""Convert PDF to HTML using external tool."""
from shutil import which
tool = os.getenv("PDF_TO_HTML_TOOL", "pdftohtml")
if not which(tool):
raise PDFToHTMLToolNotFound(
f"Command-line `{tool}` tool was not found in system PATH, was it installed?"
)
import subprocess
proc = subprocess.Popen(
[tool, '-stdout', '-', '-s', 'out.pdf', '-i'],
stdout=subprocess.PIPE,
stdin=subprocess.PIPE
)
proc.stdin.write(raw_content)
proc.stdin.close()
html_content = proc.stdout.read().decode('utf-8')
proc.wait(timeout=60)
# Add metadata for change detection
metadata = (
f"<p>Added by changedetection.io: Document checksum - "
f"{hashlib.md5(raw_content).hexdigest().upper()} "View on GitHub (pinned to 5d9c7c6da7)
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
Example fix
# before (Dockerfile) FROM python:3.12-slim COPY . /app # after FROM python:3.12-slim RUN apt-get update && apt-get install -y poppler-utils && rm -rf /var/lib/apt/lists/* COPY . /app
Defensive patterns
Strategy: validation
Validate before calling
import os
from shutil import which
tool = os.getenv('PDF_TO_HTML_TOOL', 'pdftohtml')
if not which(tool):
raise SystemExit(f'Install poppler-utils or set PDF_TO_HTML_TOOL to a valid binary') Try / catch
try:
handler.run_changedetection(watch, ...)
except PDFToHTMLToolNotFound:
alert_ops('pdftohtml missing on worker host') Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
AI-assisted analysis of dgtlmoon/changedetection.io@5d9c7c6da7 (2026-08-27).
Data as JSON: /api/errors/69c2954340d75440.
Report an issue: GitHub.