unclecode/crawl4ai · error · FileNotFoundError
Local file not found: {local_file_path}
Error message
Local file not found: {local_file_path} What it means
Raised by the Playwright-based browser crawler when a URL using the file:// scheme points to a path that does not exist on disk. The code strips the 'file://' prefix (url[7:]) and checks os.path.exists() before opening the file with utf-8 encoding. This is a fast path that skips the browser entirely and returns the file's contents as HTML.
Source
Thrown at crawl4ai/async_crawler_strategy.py:491
config.remove_consent_popups or
config.simulate_user or
config.magic or
config.process_iframes or
config.capture_console_messages or
config.capture_network_requests
)
if needs_browser:
# Route through _crawl_web() for full browser pipeline
# _crawl_web() will detect file:// and raw: URLs and use set_content()
return await self._crawl_web(url, config)
# Fast path: return HTML directly without browser interaction
if url.startswith("file://"):
# Process local file
local_file_path = url[7:] # Remove 'file://' prefix
if not os.path.exists(local_file_path):
raise FileNotFoundError(f"Local file not found: {local_file_path}")
with open(local_file_path, "r", encoding="utf-8") as f:
html = f.read()
else:
# Process raw HTML content (raw:// or raw:)
html = url[6:] if url.startswith("raw://") else url[4:]
return AsyncCrawlResponse(
html=html,
response_headers=response_headers,
status_code=status_code,
screenshot=None,
pdf_data=None,
mhtml_data=None,
get_delayed_content=None,
# For raw:/file:// URLs, use base_url if provided; don't fall back to the raw content
redirected_url=config.base_url,
)
else:View on GitHub (pinned to 7e80152142)
Solutions
- Verify the file exists and use an absolute path: pathlib.Path(...).resolve().as_uri() produces a correct file:// URL for the current OS.
- In Docker, confirm the file/directory is mounted (docker run -v) and the path inside the container matches the one in the URL.
- On Windows, prefer Path.as_uri() (yields file:///C:/...) over hand-built file:// strings.
- Check the URL encoding of spaces/special characters in the filename and percent-decode the path before checking existence.
Example fix
// before
await crawler.arun(url="file://./local/page.html")
// after
from pathlib import Path
path = Path("local/page.html").resolve()
if not path.exists():
raise FileNotFoundError(path)
await crawler.arun(url=path.as_uri()) Defensive patterns
Strategy: validation
Validate before calling
import os
from urllib.parse import urlparse, unquote
def valid_file_url(url: str) -> bool:
if not url.startswith("file://"):
return False
path = unquote(url[7:])
return os.path.isfile(path) Try / catch
try:
result = await crawler.arun(url)
except FileNotFoundError as e:
logger.warning(f"missing local file: {e}") # skip or re-queue Prevention
- Build file URLs with pathlib.Path.as_uri()
- Mount files into containers and use container-absolute paths
- Percent-decode file:// paths before existence checks
When it happens
Trigger: Calling arun()/crawl() with a URL like 'file:///path/to/page.html' where the path after removing the 7-character 'file://' prefix does not exist. Note the prefix strip keeps the leading slash, so on Windows 'file://C:/x.html' becomes '/C:/x.html' which will not resolve; relative paths or files deleted between check and open also trigger it.
Common situations: Running on a different machine or container where the absolute path differs; passing relative paths in Docker where the file is not mounted into the container; Windows drive-letter URLs; typos in the path; running tests from a different working directory.
Related errors
- Local file not found: {path}
- Profile not found: {profile_path}
- Profile not found: {profile_name_or_path}
- Container not found: ${config.container_selector}
- Timeout after {timeout}ms waiting for selector '{wait_for}'
AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14).
Data as JSON: /api/errors/3d5d1869db38b270.
Report an issue: GitHub.