crewAIInc/crewAI · error · FileNotFoundError

PDF file not found: {file_path}

Error message

PDF file not found: {file_path}

What it means

Raised by PDFLoader.load() when a local (non-URL) source path is not an existing regular file — os.path.isfile fails. This is the local-file counterpart of the download error: before pymupdf opens the path, the loader verifies it exists; directories, dangling symlinks, and missing files all fail here with FileNotFoundError.

Source

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

            source_name = Path(urlparse(file_path).path).name or "downloaded.pdf"
        else:
            source_name = Path(file_path).name

        text_content: list[str] = []
        metadata: dict[str, Any] = {
            "source": file_path,
            "file_name": source_name,
            "file_type": "pdf",
        }

        try:
            if is_url:
                doc = pymupdf.open(
                    stream=self._fetch_from_url(file_path, kwargs), filetype="pdf"
                )
            else:
                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

View on GitHub (pinned to 754d7323be)

Solutions

  1. Check existence first: Path(src).expanduser().resolve().is_file() and fail with your own context.
  2. Use absolute paths anchored to a known base instead of cwd-relative strings.
  3. If the file is produced asynchronously, wait for a completion marker (e.g. .part suffix removed) before loading.

Example fix

# before
result = PDFLoader().load(SourceContent('downloads/report.pdf'))  # cwd mismatch

# after
from pathlib import Path
pdf = Path('downloads/report.pdf').resolve()
assert pdf.is_file(), f'missing PDF: {pdf}'
result = PDFLoader().load(SourceContent(str(pdf)))
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path\n\ndef assert_pdf_file(path: str) -> None:\n    p = Path(path).expanduser().resolve()\n    if not p.is_file():\n        raise FileNotFoundError(f'PDF file not found: {p}')

Type guard

from pathlib import Path\n\ndef is_pdf_file(s: str) -> bool:\n    return s.startswith(('http://', 'https://')) or (Path(s).expanduser().is_file() and s.lower().endswith('.pdf'))

Try / catch

try:\n    result = PDFLoader().load(source)\nexcept FileNotFoundError:\n    logger.warning('missing PDF skipped: %s', source.source)\n    result = None

Prevention

When it happens

Trigger: PDFLoader().load(SourceContent('/data/missing.pdf')) where the file was never created, was deleted, lives in an unmounted volume, or the relative path resolves against the wrong cwd; also when a directory path is passed instead of a .pdf file.

Common situations: Docker deployments without the volume mounted at the expected path; notebooks where cwd differs from the project root; race conditions where the PDF is still being written/downloaded when load is called; typos or unexpanded ~ in configured paths.

Related errors


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