{"record":{"id":"c8f50fd90a6c0ae0","repo":"unclecode/crawl4ai","slug":"timeout-downloading-pdf-from-url-str-e","errorCode":null,"errorMessage":"Timeout downloading PDF from {url}: {str(e)}","messagePattern":"Timeout downloading PDF from (.+?): (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"crawl4ai/processors/pdf/__init__.py","lineNumber":183,"sourceCode":"                with open(temp_file.name, 'wb') as f:\n                    for chunk in response.iter_content(chunk_size=8192):\n                        f.write(chunk)\n                        downloaded += len(chunk)\n                        if self.logger and total_size > 0:\n                            progress = (downloaded / total_size) * 100\n                            if progress % 10 < 0.1:  # Log every 10%\n                                self.logger.debug(f\"PDF download progress: {progress:.0f}%\")\n                \n                if self.logger:\n                    self.logger.info(f\"PDF downloaded successfully: {temp_file.name}\")\n                        \n                return temp_file.name\n                \n            except requests.exceptions.Timeout as e:\n                # Clean up temp file if download fails\n                Path(temp_file.name).unlink(missing_ok=True)\n                self._temp_files.remove(temp_file.name)\n                raise RuntimeError(f\"Timeout downloading PDF from {url}: {str(e)}\")\n            except Exception as e:\n                # Clean up temp file if download fails\n                Path(temp_file.name).unlink(missing_ok=True)\n                self._temp_files.remove(temp_file.name)\n                raise RuntimeError(f\"Failed to download PDF from {url}: {str(e)}\")\n                \n        elif url.startswith(\"file://\"):\n            return url[7:]  # Strip file:// prefix\n            \n        return url  # Assume local path\n    \n\n__all__ = [\"PDFCrawlerStrategy\", \"PDFContentScrapingStrategy\"]","sourceCodeStart":165,"sourceCodeEnd":196,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/crawl4ai/processors/pdf/__init__.py#L165-L196","documentation":"Raised when a requests.exceptions.Timeout escapes while the PDF crawler strategy streams a remote PDF to a temp file. It is re-raised as RuntimeError after the temp file is unlinked and removed from the internal _temp_files list, so no partial download leaks. The message embeds the offending URL and the underlying timeout exception text.","triggerScenarios":"Calling the PDF crawler strategy's download step with an http(s) URL whose server does not respond within the requests timeout (connect or read timeout) configured for the download. Only the requests.exceptions.Timeout branch produces this message; generic failures raise the sibling 'Failed to download PDF' error.","commonSituations":"Crawling PDFs from slow or overloaded hosts, proxies or CDNs that stall mid-stream, low timeout settings in the PDF download config, or networks blocking large file transfers. Also happens when the URL points to a host that accepts connections but never finishes sending the body.","solutions":["Increase the download timeout in the PDF crawler strategy / crawl config (e.g. set a larger timeout passed to requests for PDF downloads).","Retry with backoff — transient network stalls often succeed on a second attempt.","Verify the URL is reachable (curl -I) and that it actually serves a PDF, not a login page or redirect chain that hangs.","If the host is slow by design, fetch the PDF yourself with a longer/no timeout and pass a local file:// path or local file path instead of the remote URL."],"exampleFix":"# before\nresult = await crawler.arun(url=\"https://slow-host.example/report.pdf\")  # RuntimeError: Timeout downloading PDF\n\n# after\n# raise the timeout budget for the PDF fetch (strategy kwargs / config)\npdf_strategy = PDFCrawlerStrategy(timeout=120)  # or set in config: pdf_download_timeout = 120\nresult = await crawler.arun(url=\"https://slow-host.example/report.pdf\")","handlingStrategy":"retry","validationCode":"import requests\n\ndef pdf_url_reachable(url: str, timeout: float = 10) -> bool:\n    try:\n        with requests.head(url, timeout=timeout, allow_redirects=True) as r:\n            return r.status_code == 200 and \"pdf\" in r.headers.get(\"content-type\", \"\").lower()\n    except requests.RequestException:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    result = await crawler.arun(url=pdf_url)\nexcept RuntimeError as e:\n    if \"Timeout downloading PDF\" in str(e):\n        # backoff and retry, or raise the configured timeout before next attempt\n        raise","preventionTips":["Pre-check remote PDF URLs with a HEAD request before enqueueing them.","Set a generous PDF download timeout proportional to expected file size.","Cap the crawl queue's retry count to avoid hammering dead hosts.","Prefer file:// or local paths for PDFs you can fetch yourself with custom timeouts."],"tags":["network","timeout","pdf","download","runtime-error"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}