unclecode/crawl4ai · error · RuntimeError
Failed to download PDF from {url}: {str(e)}
Error message
Failed to download PDF from {url}: {str(e)} What it means
Catch-all RuntimeError raised when any non-timeout exception occurs while the PDF crawler strategy downloads a remote PDF via requests. The temp file is cleaned up (unlink + removal from _temp_files) before raising, so disk state stays consistent. The message wraps the original exception text, which is the key to diagnosis.
Source
Thrown at crawl4ai/processors/pdf/__init__.py:188
progress = (downloaded / total_size) * 100
if progress % 10 < 0.1: # Log every 10%
self.logger.debug(f"PDF download progress: {progress:.0f}%")
if self.logger:
self.logger.info(f"PDF downloaded successfully: {temp_file.name}")
return temp_file.name
except requests.exceptions.Timeout as e:
# Clean up temp file if download fails
Path(temp_file.name).unlink(missing_ok=True)
self._temp_files.remove(temp_file.name)
raise RuntimeError(f"Timeout downloading PDF from {url}: {str(e)}")
except Exception as e:
# Clean up temp file if download fails
Path(temp_file.name).unlink(missing_ok=True)
self._temp_files.remove(temp_file.name)
raise RuntimeError(f"Failed to download PDF from {url}: {str(e)}")
elif url.startswith("file://"):
return url[7:] # Strip file:// prefix
return url # Assume local path
__all__ = ["PDFCrawlerStrategy", "PDFContentScrapingStrategy"]View on GitHub (pinned to 7e80152142)
Solutions
- Read the wrapped {str(e)} portion of the message — it identifies the root cause (DNS, TLS, HTTP status, disk).
- Test the URL directly: curl -L -o /dev/null -w '%{http_code}' <url> to confirm reachability and content type.
- For TLS errors, update certifi/CA bundle or disable verification only if the environment requires it.
- For disk errors, free space or point TMPDIR at a volume with capacity; large PDFs can exceed small temp partitions.
- If the URL requires auth or specific headers, fetch it yourself and pass a local path or file:// URL (the strategy passes those through untouched).
Example fix
# before
result = await crawler.arun(url="https://example.com/reports/report.pdf") # RuntimeError: Failed to download PDF ... SSLError
# after
import requests, pathlib
resp = requests.get(url, headers={"Authorization": "Bearer ..."}, timeout=120)
resp.raise_for_status()
local = pathlib.Path("/tmp/report.pdf"); local.write_bytes(resp.content)
result = await crawler.arun(url=local.as_uri()) # file:// path bypasses the downloader Defensive patterns
Strategy: try-catch
Validate before calling
import requests
def check_pdf_download(url: str) -> tuple[bool, str]:
try:
r = requests.get(url, timeout=30, stream=True)
r.raise_for_status()
ct = r.headers.get("content-type", "")
return ("pdf" in ct.lower(), ct)
except requests.RequestException as e:
return (False, str(e)) Try / catch
try:
result = await crawler.arun(url=pdf_url)
except RuntimeError as e:
if "Failed to download PDF" in str(e):
logger.error(f"PDF fetch failed: {str(e).split(': ', 1)[-1]}") # root cause is in the wrapped text
mark_url_failed(pdf_url) Prevention
- Read the wrapped exception text — it distinguishes DNS, TLS, HTTP, and disk failures.
- Validate URLs (scheme, domain) before enqueueing; drop obviously malformed ones.
- Keep CA certificates current in containers (apt install ca-certificates / pip install -U certifi).
- Ensure TMPDIR has free space for large PDFs.
When it happens
Trigger: Passing an http(s) URL to the PDF download step that triggers requests exceptions other than Timeout: ConnectionError (DNS failure, refused connection), HTTPError-class failures surfaced during streaming, TLS/SSL verification errors, chunked decode errors, or disk errors writing the temp file.
Common situations: 404/dead links, mistyped domains (DNS failure), corporate proxies or TLS interception breaking HTTPS, missing CA certificates, disk full while writing the temp file, or remote servers dropping the connection mid-download.
Related errors
- Timeout downloading PDF from {url}: {str(e)}
- Failed on navigating ACS-GOTO: {str(e)}
- Unexpected status code for {url}
- Request timed out: {str(e)}
- Connection failed: {str(e)}
AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14).
Data as JSON: /api/errors/33382a3cb3e12e31.
Report an issue: GitHub.