crewAIInc/crewAI · error · ValueError

Error reading PDF from {file_path}: {e!s}

Error message

Error reading PDF from {file_path}: {e!s}

What it means

Thrown by PDFFileLoader.load when pymupdf (fitz) raises while opening or extracting text from a PDF. The loader wraps any non-FileNotFoundError exception (e.g. pymupdf's RuntimeError for corrupted or encrypted files) into a ValueError with the file path and underlying message. It is a load-time failure of the RAG ingestion step, not a config error.

Source

Thrown at lib/crewai-tools/src/crewai_tools/rag/loaders/pdf_loader.py:129

                if not os.path.isfile(file_path):
                    raise FileNotFoundError(f"PDF file not found: {file_path}")
                doc = pymupdf.open(file_path)

            # Closed in a finally so a failure mid-extraction still releases the
            # document handle.
            try:
                metadata["num_pages"] = len(doc)

                for page_num, page in enumerate(doc, 1):
                    page_text = page.get_text()
                    if page_text.strip():
                        text_content.append(f"Page {page_num}:\n{page_text}")
            finally:
                doc.close()
        except FileNotFoundError:
            raise
        except Exception as e:
            raise ValueError(f"Error reading PDF from {file_path}: {e!s}") from e

        if not text_content:
            content = f"[PDF file with no extractable text: {source_name}]"
        else:
            content = "\n\n".join(text_content)

        return LoaderResult(
            content=content,
            source=file_path,
            metadata=metadata,
            doc_id=self.generate_doc_id(source_ref=file_path, content=content),
        )

View on GitHub (pinned to 754d7323be)

Solutions

  1. Verify the file is a real, complete PDF before loading (check magic bytes '%PDF-' and that it ends with '%%EOF' or re-download it).
  2. Test opening it directly: python -c "import fitz; d=fitz.open('file.pdf'); print(d.page_count)" to surface the raw pymupdf error.
  3. If the PDF is encrypted, decrypt it first with the password (fitz Document.authenticate) or with a tool like qpdf before ingestion.
  4. Upgrade pymupdf to the latest version (uv add 'pymupdf>=1.24') since parse failures are often fixed upstream.
  5. If the file genuinely does not exist, let the FileNotFoundError propagate (the loader re-raises it unchanged) and fix the path.

Example fix

// before
result = pdf_loader.load(SourceContent(path="report.pdf"))

# after
import fitz

def is_readable_pdf(path: str) -> bool:
    try:
        doc = fitz.open(path)
        doc.close()
        return True
    except Exception:
        return False

if is_readable_pdf("report.pdf"):
    result = pdf_loader.load(SourceContent(path="report.pdf"))
else:
    log.warning("skipping unreadable PDF: %s", "report.pdf")
Defensive patterns

Strategy: try-catch

Validate before calling

import fitz

def pdf_is_loadable(path: str) -> bool:
    try:
        doc = fitz.open(path)
        try:
            if doc.is_encrypted and not doc.authenticate(""):
                return False
            _ = doc[0].get_text()
            return True
        finally:
            doc.close()
    except Exception:
        return False

Try / catch

try:
    result = pdf_loader.load(src)
except FileNotFoundError:
    skip(src)  # missing file, distinct signal
except ValueError as e:
    log.warning("pdf parse failed src=%s cause=%r", src.source, e.__cause__)
    quarantine(src)

Prevention

When it happens

Trigger: Calling loader.load(SourceContent(path='broken.pdf')) or RagService ingestion on a file that fitz.open() cannot parse: truncated downloads, password-protected/encrypted PDFs, zero-byte files, or files with a .pdf extension that are not actually PDFs. Also triggered if the file disappears between the existence check and open (TOCTOU) or by unsupported/odd PDF structures.

Common situations: Ingesting user-uploaded or scraped documents where some downloads are truncated; encrypted PDFs from financial/government sites; a pipeline pointed at a directory with mixed file types; older pymupdf versions failing on newer PDF features.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/450043f1564baaad. Report an issue: GitHub.