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
- Verify the file is a real, complete PDF before loading (check magic bytes '%PDF-' and that it ends with '%%EOF' or re-download it).
- Test opening it directly: python -c "import fitz; d=fitz.open('file.pdf'); print(d.page_count)" to surface the raw pymupdf error.
- If the PDF is encrypted, decrypt it first with the password (fitz Document.authenticate) or with a tool like qpdf before ingestion.
- Upgrade pymupdf to the latest version (uv add 'pymupdf>=1.24') since parse failures are often fixed upstream.
- 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
- Validate downloads with a magic-byte check (%PDF- header) before ingestion.
- Skip or password-decrypt encrypted PDFs upstream of the RAG pipeline.
- Batch-ingest with per-file try/except so one bad PDF does not kill the run.
- Keep pymupdf current; most parse regressions are fixed upstream.
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
- The following file does not exist: {source_content.source}
- Reading PDF URLs requires pymupdf. Install with: uv add pymu
- pypdf is required for PDF chunking
- PDF '{filename}' page count ({page_count}) exceeds maximum (
- Client is not initialized
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/450043f1564baaad.
Report an issue: GitHub.