crewAIInc/crewAI · error · ValueError

Failed to download PDF from {url}: {e!s}

Error message

Failed to download PDF from {url}: {e!s}

What it means

Raised by PDFLoader._fetch_from_url() when anything fails while downloading a remote PDF: the bounded safe_get_bounded request (network error, HTTP error status after raise, exceeded max_bytes cap), or exceptions raised while returning the body. The broad except wraps it into ValueError with the URL and stringified cause.

Source

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

        """
        headers = kwargs.get(
            "headers",
            {
                "Accept": "application/pdf",
                "User-Agent": "Mozilla/5.0 (compatible; crewai-tools PDFLoader)",
            },
        )

        try:
            body, _content_type, _final_url = safe_get_bounded(
                url,
                max_bytes=kwargs.get("max_bytes", DEFAULT_MAX_PDF_BYTES),
                headers=headers,
                timeout=30,
            )
            return body
        except Exception as e:
            raise ValueError(f"Failed to download PDF from {url}: {e!s}") from e

    def load(self, source: SourceContent, **kwargs: Any) -> LoaderResult:  # type: ignore[override]
        """Load and extract text from a PDF file or URL.

        Args:
            source: The source content containing the PDF file path or URL.

        Returns:
            LoaderResult with extracted text content.

        Raises:
            FileNotFoundError: If the PDF file doesn't exist.
            ImportError: If required PDF libraries aren't installed.
            ValueError: If the PDF cannot be read or downloaded.
        """
        try:
            import pymupdf  # type: ignore[import-untyped]
        except ImportError as e:

View on GitHub (pinned to 754d7323be)

Solutions

  1. Verify the link with curl -I — confirm 200 and application/pdf; fix or re-generate the URL.
  2. For large PDFs, raise the cap: PDFLoader().load(src, max_bytes=50_000_000).
  3. Retry transient failures once; cache downloaded PDFs locally and pass the file path on subsequent runs.
  4. If the server blocks the default user-agent, download with your own session/headers and pass the local file.

Example fix

# before
result = PDFLoader().load(SourceContent('https://example.com/big-report.pdf'))  # > max_bytes

# after
result = PDFLoader().load(
    SourceContent('https://example.com/big-report.pdf'),
    max_bytes=100 * 1024 * 1024,
)
Defensive patterns

Strategy: retry

Validate before calling

import requests\n\ndef pdf_url_ok(url: str) -> bool:\n    try:\n        r = requests.head(url, timeout=10, allow_redirects=True)\n        return r.ok and 'pdf' in r.headers.get('Content-Type', '')\n    except requests.RequestException:\n        return False

Try / catch

try:\n    result = PDFLoader().load(source)\nexcept ValueError as e:\n    if 'Failed to download PDF' in str(e):\n        result = cached_or_retry_later(source.source)\n    else:\n        raise

Prevention

When it happens

Trigger: PDFLoader().load(SourceContent('https://example.com/paper.pdf')) where the URL 404s, the host is unreachable/TLS fails, the download exceeds max_bytes (default DEFAULT_MAX_PDF_BYTES) and is aborted, or the request times out at 30s.

Common situations: Broken/expired links to PDFs; sites requiring cookies or blocking non-browser agents; very large PDFs exceeding the byte cap; flaky mobile/corporate networks; PDF URLs that actually return HTML (though that usually fails later at parse time).

Related errors


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