Skip to content

fix: read file:// URLs built by Path.as_uri(), including Windows drive paths - #2452

Open
tanishqbaweja wants to merge 1 commit into
unclecode:developfrom
tanishqbaweja:fix/file-url-local-paths
Open

tanishqbaweja wants to merge 1 commit into
unclecode:developfrom
tanishqbaweja:fix/file-url-local-paths

Conversation

@tanishqbaweja

@tanishqbaweja tanishqbaweja commented Oct 28, 2026 •

Copy link
Copy Markdown

Summary

Standard file:// URLs, such as those built by Path.as_uri() or copied from a browser's address bar, fail with FileNotFoundError when the path contains a space or any other percent-encoded character. On Windows they fail for every path. I found this on Windows and couldn't find an existing issue for it.

  • AsyncPlaywrightCrawlerStrategy takes url[7:] without decoding the URL. On Windows, file:///C:/Users/me/page.html turns into /C:/Users/me/page.html, which doesn't exist. The path also stays percent-encoded, so on every OS a path with a space fails (my%20docs).
  • AsyncHTTPCrawlerStrategy uses urlparse(url).path, which has the same two problems. On Windows it also breaks the documented f"file://{path}" form: urlparse puts C:\Users\... in the netloc, so the path is empty (Local file not found: ).

The fix adds a small _file_url_to_path() helper. If the file at the plain prefix-stripped path exists, the helper returns that path, so URLs that work today behave as before. Otherwise it decodes the URL with url2pathname(), which handles standard file URLs, including file://localhost/.... The fast path, the browser path and the HTTP strategy all use it now. A missing file still raises FileNotFoundError.

List of files changed and why

  • crawl4ai/async_crawler_strategy.py: adds _file_url_to_path() next to the other shared helper, _safe_download_filepath(), and uses it at the three file:// sites (Playwright fast path, Playwright browser path, AsyncHTTPCrawlerStrategy.crawl).
  • tests/test_file_url_local_paths.py: new regression tests. Both strategies read a file through Path.as_uri() and through f"file://{path}", from a folder with a space in its name. A missing file still raises FileNotFoundError. No browser or network is needed.

Not changed here: PDFContentScrapingStrategy._get_pdf_path still strips the prefix the same way. It could use the same helper in a follow-up.

How Has This Been Tested?

I ran everything natively on Windows 11 with Python 3.12 and Playwright Chromium.

  • pytest tests/test_file_url_local_paths.py

    • On develop: 3 failed, 5 passed. Playwright as_uri fails with Local file not found: /C:/Users/.../my%20docs/page.html, and so does HTTP as_uri. HTTP f"file://{path}" fails with Local file not found: (an empty path).
    • With this change: 8 passed.
  • End to end with AsyncWebCrawler.arun() on a page in a folder named my docs, for each URL form with process_in_browser set to False and to True:

    URL form process_in_browser develop this PR
    page.as_uri() False FileNotFoundError content read
    page.as_uri() True FileNotFoundError content read
    f"file://{page}" False content read content read
    f"file://{page}" True content read content read
  • pytest tests/test_raw_html_edge_cases.py -k file_url: test_file_url_fast_path and test_file_url_with_js_code fail the same way on develop and with this change. The file is read, but the anti-bot check rejects the small test pages ("Near-empty content (48 bytes)" and "(89 bytes) with HTTP 200"), so the failures are unrelated to this change.

  • black --check tests/test_file_url_local_paths.py passes. async_crawler_strategy.py isn't black-formatted on develop, so I didn't reformat it; black leaves the changed lines as they are.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (not needed: the documented f"file://{path}" form keeps working)
  • I have added/updated unit tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes (the new tests pass; the two file_url tests in test_raw_html_edge_cases.py fail on develop too, as described above)

…e paths

Both crawler strategies stripped the "file://" prefix (or used
urlparse().path) without decoding the URL. Standard file URLs, as built by
Path.as_uri() or copied from a browser, raised FileNotFoundError:

- the path is percent-encoded, so any path with a space failed on every OS
- on Windows the drive follows a slash (file:///C:/...), which left "/C:/..."
- on Windows AsyncHTTPCrawlerStrategy got an empty path for the documented
  f"file://{path}" form, because urlparse puts "C:\..." in the netloc

Add _file_url_to_path(): keep the plain prefix strip when that file exists
(so existing callers are unchanged), otherwise decode the URL with
url2pathname(). Use it in the fast path, the browser path and the HTTP
strategy.
@tanishqbaweja
tanishqbaweja force-pushed the fix/file-url-local-paths branch from 89ceea9 to 57cbbd1 Compare October 28, 2026 07:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant