unclecode/crawl4ai · error · HTTPCrawlerError
HTTP request failed: {str(e)}
Error message
HTTP request failed: {str(e)} What it means
The catch-all handler in the HTTP-mode crawler: any exception that is not ServerTimeoutError, ClientConnectorError, ClientError, or asyncio.TimeoutError is wrapped in HTTPCrawlerError with 'HTTP request failed'. This captures unexpected failures such as decoding errors, SSL context problems surfaced as non-aiohttp exceptions, or bugs in user hooks registered on 'before_request'/'after_request'.
Source
Thrown at crawl4ai/async_crawler_strategy.py:2796
except aiohttp.ServerTimeoutError as e:
await self.hooks['on_error'](e)
raise ConnectionTimeoutError(f"Request timed out: {str(e)}")
except aiohttp.ClientConnectorError as e:
await self.hooks['on_error'](e)
raise ConnectionError(f"Connection failed: {str(e)}")
except aiohttp.ClientError as e:
await self.hooks['on_error'](e)
raise HTTPCrawlerError(f"HTTP client error: {str(e)}")
except asyncio.exceptions.TimeoutError as e:
await self.hooks['on_error'](e)
raise ConnectionTimeoutError(f"Request timed out: {str(e)}")
except Exception as e:
await self.hooks['on_error'](e)
raise HTTPCrawlerError(f"HTTP request failed: {str(e)}")
async def crawl(
self,
url: str,
config: Optional[CrawlerRunConfig] = None,
**kwargs
) -> AsyncCrawlResponse:
config = config or CrawlerRunConfig.from_kwargs(kwargs)
parsed = urlparse(url)
scheme = parsed.scheme.rstrip('/')
if scheme not in self.VALID_SCHEMES:
raise ValueError(f"Unsupported URL scheme: {scheme}")
try:
if scheme == 'file':
return await self._handle_file(parsed.path)View on GitHub (pinned to 7e80152142)
Solutions
- Read the wrapped original exception text — it names the real failing operation.
- Audit custom hooks registered via set_hook('before_request'/'after_request') for exceptions and argument mutation errors.
- Reproduce the URL with plain aiohttp in a script to isolate whether crawl4ai or the environment is at fault.
- Wrap the crawl call in try/except HTTPCrawlerError to keep batch runs alive.
Example fix
// before
strategy.set_hook('before_request', lambda url, kw: kw.update(timeout='30')) # wrong type, raises
// after
async def before_request(url, request_kwargs):
request_kwargs['timeout'] = 30
strategy.set_hook('before_request', before_request) Defensive patterns
Strategy: try-catch
Try / catch
from crawl4ai.async_crawler_strategy import HTTPCrawlerError
try:
result = await crawler.arun(url)
except HTTPCrawlerError as e:
logger.exception(f"unexpected crawl failure for {url}")
raise Prevention
- Keep before_request/after_request hooks exception-free
- Log the wrapped cause, not just the wrapper
- Reproduce failing URLs with plain aiohttp to isolate the fault
When it happens
Trigger: A user hook raising an arbitrary exception during before_request/after_request (on_error hook runs first, then re-raised wrapped); response body decoding issues; environment-level SSL module errors; any programming error inside the request path.
Common situations: Custom before_request hooks that mutate request_kwargs incorrectly (e.g. setting a non-serializable value) and raise; exotic TLS environments; bugs that only surface for specific URLs.
Related errors
- Unexpected status code for {url}
- Request timed out: {str(e)}
- Connection failed: {str(e)}
- HTTP client error: {str(e)}
- Failed to evaluate wait condition: {str(e)}
AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14).
Data as JSON: /api/errors/6764a233dccca20c.
Report an issue: GitHub.