docling-project/docling · error · DocumentLoadError

pypdfium could not load document with hash {self.document_ha

Error message

pypdfium could not load document with hash {self.document_hash}

What it means

DocumentLoadError raised by the pypdfium2 backend constructor when pdfium.PdfDocument() raises PdfiumError for the given path/stream (including a failed password attempt via options.password). The original PdfiumError is chained; the message carries document_hash for correlation.

Source

Thrown at docling/backend/pypdfium2_backend.py:427

class PyPdfiumDocumentBackend(ManagedPdfiumDocumentBackend):
    def __init__(
        self,
        in_doc: "InputDocument",
        path_or_stream: Union[BytesIO, Path],
        options: Optional[PdfBackendOptions] = None,
    ):
        if options is None:
            options = PdfBackendOptions()
        super().__init__(in_doc, path_or_stream, options)

        password = (
            self.options.password.get_secret_value() if self.options.password else None
        )
        try:
            with pypdfium2_lock:
                self._pdoc = pdfium.PdfDocument(self.path_or_stream, password=password)
        except PdfiumError as e:
            raise DocumentLoadError(
                f"pypdfium could not load document with hash {self.document_hash}"
            ) from e

    def page_count(self) -> int:
        with pypdfium2_lock:
            return len(self._pdoc)

    def load_page(self, page_no: int) -> PyPdfiumPageBackend:
        with pypdfium2_lock:
            return PyPdfiumPageBackend(self._pdoc, self.document_hash, page_no)

    def is_valid(self) -> bool:
        return self.page_count() > 0

    def get_document_outline(self) -> list[_PdfOutlineItem]:
        """Extract the PDF outline from the pypdfium2 document (title, depth, page, position)."""
        if self._pdoc is None:
            return []

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. If the PDF is encrypted, pass the password: PdfBackendOptions(password=SecretStr('...')) on the format option (e.g. InputFormat.PDF options pipeline).
  2. Validate the header first: the first bytes should be '%PDF-'; re-download truncated files.
  3. Try repairing with qpdf --decrypt or ghostscript, then retry.
  4. Fall back to the docling-parse PDF backend (pdf_backend) if pypdfium2 cannot parse a specific file.

Example fix

# before
res = converter.convert(Path('locked.pdf'))  # DocumentLoadError: pypdfium could not load

# after
from docling.datamodel.pipeline_options import PdfPipelineOptions
opts = PdfPipelineOptions()
from docling.datamodel.settings import PdfBackendOptions  # password lives on backend options
pipeline_options = PdfPipelineOptions(pdf_backend_options=None)
# simplest: set format options password
conv = DocumentConverter(
    format_options={InputFormat.PDF: PdfFormatOptions(pipeline_options=opts)}
)
Defensive patterns

Strategy: try-catch

Validate before calling

with open(path, 'rb') as f:
    header = f.read(5)
if header != b'%PDF-':
    raise ValueError('file is not a PDF')

Try / catch

from docling.exceptions import DocumentLoadError
try:
    result = converter.convert(path)
except DocumentLoadError as e:
    cause = e.__cause__
    if 'password' in str(cause).lower():
        result = converter.convert_with_password(path, pw)
    else:
        raise

Prevention

When it happens

Trigger: Converting a corrupted or password-protected PDF without the correct PdfBackendOptions.password; empty or truncated PDF bytes; a file that is not a PDF at all. pypdfium2_lock serializes the call, then the except converts PdfiumError to DocumentLoadError.

Common situations: Scanned PDFs from scanners that produce slightly malformed files, encrypted PDFs from banks/HR, downloads interrupted mid-stream, and PDFs served with HTML error pages saved as .pdf.

Related errors


AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14). Data as JSON: /api/errors/82238235665e9a14. Report an issue: GitHub.