unclecode/crawl4ai · error · RuntimeError
Unsupported browser type: {browser_type}
Error message
Unsupported browser type: {browser_type} What it means
RuntimeError from get_browser_executable_path (utils.py) when browser_type is not one of chromium/firefox/webkit. The dict lookup reassigns browser_type to None for unknown keys and the falsy check raises. Note the message interpolates the already-overwritten variable, so it prints 'Unsupported browser type: None' — the original input is lost.
Source
Thrown at crawl4ai/utils.py:654
Uses playwright's built-in browser management to get the correct browser executable
path regardless of platform. This ensures we're using the same browser version
that playwright is tested with.
Returns:
str: Path to browser executable
Raises:
RuntimeError: If browser executable cannot be found
"""
browser_types = {
"chromium": "chromium",
"firefox": "firefox",
"webkit": "webkit"
}
browser_type = browser_types.get(browser_type)
if not browser_type:
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(View on GitHub (pinned to 7e80152142)
Solutions
- Use exactly 'chromium', 'firefox', or 'webkit' (Playwright's browser names, not vendor names).
- Normalize user input at your boundary: {'chrome': 'chromium', 'msedge': 'chromium'}.get(name.lower(), name.lower()).
- Also note this legacy helper predates the dict-based check just below (which lowercases input) — prefer passing already-lowercased canonical names.
Example fix
# before
path = await get_browser_executable_path("chrome") # RuntimeError: Unsupported browser type: None
# after
alias = {"chrome": "chromium", "edge": "chromium"}.get(name.lower(), name.lower())
path = await get_browser_executable_path("chromium") Defensive patterns
Strategy: validation
Validate before calling
VALID_BROWSERS = {"chromium", "firefox", "webkit"}
def canonical_browser(name: str) -> str:
aliases = {"chrome": "chromium", "edge": "chromium", "msedge": "chromium", "brave": "chromium"}
n = name.strip().lower()
return aliases.get(n, n)
# assert canonical_browser(user_input) in VALID_BROWSERS before calling Type guard
def is_valid_browser_type(name: str) -> bool:
return isinstance(name, str) and name.lower() in {"chromium", "firefox", "webkit"} Try / catch
try:
path = await get_browser_executable_path(browser)
except (RuntimeError, ValueError) as e:
if 'browser type' in str(e):
raise ValueError(f"Use chromium/firefox/webkit, got {browser!r}") from e Prevention
- Use Playwright browser names (chromium/firefox/webkit), never vendor names like 'chrome'.
- Normalize aliases at your config boundary before passing through.
- Note the bug: this message prints 'None' because browser_type is overwritten — check your input, not the message.
When it happens
Trigger: Passing browser_type values like 'chrome', 'msedge', 'brave', or any casing/typo variant that doesn't exactly match the three Playwright browser keys before the lookup.
Common situations: Users naturally writing 'chrome' instead of 'chromium', passing headless-shell or channel names, or forwarding a user-configured browser name unchecked into the setup helper.
Related errors
- Invalid browser type. Must be one of: {', '.join(browsers.ke
- [NSTProxy] Invalid protocol: {protocol}
- concurrency must be positive
- timeout must be positive
- max_links must be positive
AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14).
Data as JSON: /api/errors/3ddf79072b150e1c.
Report an issue: GitHub.