unclecode/crawl4ai · error · ValueError
Invalid browser type. Must be one of: {', '.join(browsers.ke
Error message
Invalid browser type. Must be one of: {', '.join(browsers.keys())} What it means
ValueError raised in the Playwright-based path-resolution branch of get_browser_executable_path when browser_type.lower() is not a key of the locally built browsers dict ({'chromium','firefox','webkit'}). This check runs after a cached .path file lookup misses, right before querying Playwright's executable_path.
Source
Thrown at crawl4ai/utils.py:672
raise RuntimeError(f"Unsupported browser type: {browser_type}")
# Check if a path has already been saved for this browser type
home_folder = get_home_folder()
path_file = os.path.join(home_folder, f"{browser_type.lower()}.path")
if os.path.exists(path_file):
with open(path_file, "r") as f:
return f.read()
from playwright.async_api import async_playwright
async with async_playwright() as p:
browsers = {
'chromium': p.chromium,
'firefox': p.firefox,
'webkit': p.webkit
}
if browser_type.lower() not in browsers:
raise ValueError(
f"Invalid browser type. Must be one of: {', '.join(browsers.keys())}"
)
# Save the path int the crawl4ai home folder
home_folder = get_home_folder()
browser_path = browsers[browser_type.lower()].executable_path
if not browser_path:
raise RuntimeError(f"Browser executable not found for type: {browser_type}")
# Save the path in a text file with browser type name
with open(os.path.join(home_folder, f"{browser_type.lower()}.path"), "w") as f:
f.write(browser_path)
return browser_path
def beautify_html(escaped_html):
"""
Beautifies an escaped HTML string.
View on GitHub (pinned to 7e80152142)
Solutions
- Pass one of the canonical Playwright names: 'chromium', 'firefox', 'webkit' (any case).
- Map vendor aliases to Playwright names before calling.
- Prefer crawl4ai's higher-level setup API (crawl4ai-setup) which handles browser installation and naming for you.
Example fix
# before
path = await get_browser_executable_path("Chrome") # ValueError: Invalid browser type. Must be one of: chromium, firefox, webkit
# after
path = await get_browser_executable_path("chromium") Defensive patterns
Strategy: type-guard
Validate before calling
BROWSERS = {"chromium", "firefox", "webkit"}
if browser_type.lower() not in BROWSERS:
raise ValueError(f"browser_type must be one of {sorted(BROWSERS)}, got {browser_type!r}")
path = await get_browser_executable_path(browser_type) Type guard
def is_playwright_browser(name: str) -> bool:
return isinstance(name, str) and name.lower() in {"chromium", "firefox", "webkit"} Try / catch
try:
path = await get_browser_executable_path(name)
except ValueError as e:
if 'Invalid browser type' in str(e):
name = canonical_browser(name) # retry with normalized alias
path = await get_browser_executable_path(name) Prevention
- Any casing works here, but the name itself must be one of the three Playwright browsers.
- Validate config values at load time with the set membership check above.
- Prefer crawl4ai's setup entry points which normalize browser names for you.
When it happens
Trigger: Calling the async setup utility with an unrecognized browser type when no cached path file exists for it — the code lowercases the input then requires one of Playwright's three browser names.
Common situations: Same misuse class as the sibling RuntimeError: 'chrome' vs 'chromium', vendor names, or passing a full executable path instead of a browser type. The lowercase handling here means uppercase 'CHROMIUM' works, but 'chrome' still fails.
Related errors
- Unsupported browser type: {browser_type}
- Browser executable not found for type: {browser_type}
- Container not found: ${config.container_selector}
- Timeout after {timeout}ms waiting for selector '{wait_for}'
- [NSTProxy] token and channel_id are required
AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14).
Data as JSON: /api/errors/6812a3b1f0cc6311.
Report an issue: GitHub.