unclecode/crawl4ai · critical · Exception
Failed to start browser: {e}
Error message
Failed to start browser: {e} What it means
BrowserManager.start() wraps its whole body in try/except: any failure while spawning the browser subprocess or during the initial startup check (0.5s + 2s grace, _initial_startup_check) triggers cleanup() and re-raises the generic message 'Failed to start browser: {e}' with the underlying error embedded. The original exception type is lost — it becomes a plain Exception.
Source
Thrown at crawl4ai/browser_manager.py:277
stderr=subprocess.PIPE,
preexec_fn=os.setpgrp # Start in a new process group
)
# If verbose is True print args used to run the process
if self.logger and self.browser_config.verbose:
self.logger.debug(
f"Starting browser with args: {' '.join(args)}",
tag="BROWSER"
)
# We'll monitor for a short time to make sure it starts properly, but won't keep monitoring
await asyncio.sleep(0.5) # Give browser time to start
await self._initial_startup_check()
await asyncio.sleep(2) # Give browser time to start
return f"http://{self.host}:{self.debugging_port}"
except Exception as e:
await self.cleanup()
raise Exception(f"Failed to start browser: {e}")
async def _initial_startup_check(self):
"""
Perform a quick check to make sure the browser started successfully.
This only runs once at startup rather than continuously monitoring.
"""
if not self.browser_process:
return
# Check that process started without immediate termination
await asyncio.sleep(0.5)
if self.browser_process.poll() is not None:
# Process already terminated
stdout, stderr = b"", b""
try:
stdout, stderr = self.browser_process.communicate(timeout=0.5)
except subprocess.TimeoutExpired:
passView on GitHub (pinned to 7e80152142)
Solutions
- Read the ': {e}' suffix — it names the real failure (FileNotFoundError, Address already in use, etc.) and fix that.
- Verify the browser binary exists: point BrowserConfig(browser_path='/usr/bin/chromium') explicitly or install Chrome/Chromium.
- If the port is taken, change BrowserConfig(headless=True, debugging_port=<free port>) or kill the stale process.
- In Docker, add --shm-size=1g or BrowserConfig(extra_args=['--no-sandbox','--disable-dev-shm-usage']) for sandbox/shared-memory crashes.
- Enable verbose logging (BrowserConfig(verbose=True)) to see the exact launch args and stderr.
Example fix
# before
browser_config = BrowserConfig(browser_type='chromium') # binary not found -> Failed to start browser
# after
browser_config = BrowserConfig(
browser_type='chromium',
headless=True,
extra_args=['--no-sandbox', '--disable-dev-shm-usage'],
) Defensive patterns
Strategy: retry
Validate before calling
import shutil
binary = shutil.which('chromium') or shutil.which('google-chrome') or shutil.which('chrome')
if not binary:
raise SystemExit('no Chromium/Chrome binary found; install it or set browser_path') Try / catch
for attempt in range(3):
try:
async with AsyncWebCrawler(config=browser_config) as crawler:
results = await crawler.arun(url)
break
except Exception as e:
if 'Failed to start browser' in str(e) and attempt < 2:
await asyncio.sleep(2)
continue
raise Prevention
- Pre-flight check the browser binary path before starting crawls.
- In Docker add --shm-size and --no-sandbox args.
- Log the ': {e}' suffix to capture the real launch error.
- Keep a free debugging_port per instance.
When it happens
Trigger: Browser executable missing or wrong browser_type/browser_path in BrowserConfig; the spawned process exits immediately (bad flags, incompatible Chrome version); port already in use for --remote-debugging-port; sandbox/permission errors in Docker; _initial_startup_check detecting early process death.
Common situations: Fresh environments without Chrome/Chromium installed; Docker containers missing shared-memory flags (--shm-size) causing early Chromium crashes; wrong browser_path pointing at a non-existent binary; SELinux/AppArmor denying exec; version drift between Playwright and installed Chrome.
Related errors
- CDP endpoint at {cdp_url} is not ready after startup
- Browser executable not found for type: {browser_type}
- Failed on navigating ACS-GOTO: {str(e)}
- Body element is hidden: {visibility_info}
- Failed to extract HTML content: {str(e)}
AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14).
Data as JSON: /api/errors/348a6f2078a49a41.
Report an issue: GitHub.