{"record":{"id":"3d5d1869db38b270","repo":"unclecode/crawl4ai","slug":"local-file-not-found-local-file-path","errorCode":null,"errorMessage":"Local file not found: {local_file_path}","messagePattern":"Local file not found: (.+?)","errorType":"exception","errorClass":"FileNotFoundError","httpStatus":null,"severity":"error","filePath":"crawl4ai/async_crawler_strategy.py","lineNumber":491,"sourceCode":"                config.remove_consent_popups or\n                config.simulate_user or\n                config.magic or\n                config.process_iframes or\n                config.capture_console_messages or\n                config.capture_network_requests\n            )\n\n            if needs_browser:\n                # Route through _crawl_web() for full browser pipeline\n                # _crawl_web() will detect file:// and raw: URLs and use set_content()\n                return await self._crawl_web(url, config)\n\n            # Fast path: return HTML directly without browser interaction\n            if url.startswith(\"file://\"):\n                # Process local file\n                local_file_path = url[7:]  # Remove 'file://' prefix\n                if not os.path.exists(local_file_path):\n                    raise FileNotFoundError(f\"Local file not found: {local_file_path}\")\n                with open(local_file_path, \"r\", encoding=\"utf-8\") as f:\n                    html = f.read()\n            else:\n                # Process raw HTML content (raw:// or raw:)\n                html = url[6:] if url.startswith(\"raw://\") else url[4:]\n\n            return AsyncCrawlResponse(\n                html=html,\n                response_headers=response_headers,\n                status_code=status_code,\n                screenshot=None,\n                pdf_data=None,\n                mhtml_data=None,\n                get_delayed_content=None,\n                # For raw:/file:// URLs, use base_url if provided; don't fall back to the raw content\n                redirected_url=config.base_url,\n            )\n        else:","sourceCodeStart":473,"sourceCodeEnd":509,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/crawl4ai/async_crawler_strategy.py#L473-L509","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait crawler.arun(url=\"file://./local/page.html\")\n\n// after\nfrom pathlib import Path\npath = Path(\"local/page.html\").resolve()\nif not path.exists():\n    raise FileNotFoundError(path)\nawait crawler.arun(url=path.as_uri())","handlingStrategy":"validation","validationCode":"import os\nfrom urllib.parse import urlparse, unquote\n\ndef valid_file_url(url: str) -> bool:\n    if not url.startswith(\"file://\"):\n        return False\n    path = unquote(url[7:])\n    return os.path.isfile(path)","typeGuard":null,"tryCatchPattern":"try:\n    result = await crawler.arun(url)\nexcept FileNotFoundError as e:\n    logger.warning(f\"missing local file: {e}\")  # skip or re-queue","preventionTips":["Build file URLs with pathlib.Path.as_uri()","Mount files into containers and use container-absolute paths","Percent-decode file:// paths before existence checks"],"tags":["local-file","file-url","filesystem","validation"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}