{"record":{"id":"0251bff83bb12388","repo":"unclecode/crawl4ai","slug":"browser-is-not-available-it-may-have-been-closed","errorCode":null,"errorMessage":"Browser is not available. It may have been closed, crashed, or not yet started. Ensure the browser is running before creating new contexts.","messagePattern":"Browser is not available\\. It may have been closed, crashed, or not yet started\\. Ensure the browser is running before creating new contexts\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"crawl4ai/browser_manager.py","lineNumber":1268,"sourceCode":"            for script in self.config.init_scripts:\n                await context.add_init_script(script)\n\n    async def create_browser_context(self, crawlerRunConfig: CrawlerRunConfig = None):\n        \"\"\"\n        Creates and returns a new browser context with configured settings.\n        Applies text-only mode settings if text_mode is enabled in config.\n\n        Returns:\n            Context: Browser context object with the specified configurations\n        \"\"\"\n        if self.browser is None:\n            if self._launched_persistent:\n                raise RuntimeError(\n                    \"Cannot create new browser contexts when using \"\n                    \"use_persistent_context=True. Persistent context uses a \"\n                    \"single shared context.\"\n                )\n            raise RuntimeError(\n                \"Browser is not available. It may have been closed, crashed, \"\n                \"or not yet started. Ensure the browser is running before \"\n                \"creating new contexts.\"\n            )\n        # Base settings\n        user_agent = self.config.headers.get(\"User-Agent\", self.config.user_agent) \n        viewport_settings = {\n            \"width\": self.config.viewport_width,\n            \"height\": self.config.viewport_height,\n        }\n        proxy_settings = {\"server\": self.config.proxy} if self.config.proxy else None\n\n        # CSS extensions (blocked separately via avoid_css flag)\n        css_extensions = [\"css\", \"less\", \"scss\", \"sass\"]\n\n        # Static resource extensions (blocked when text_mode is enabled)\n        static_extensions = [\n            # Images","sourceCodeStart":1250,"sourceCodeEnd":1286,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/crawl4ai/browser_manager.py#L1250-L1286","documentation":"The sibling guard in create_browser_context(): self.browser is None and the manager was NOT launched persistently, meaning the Playwright Browser handle is gone — it was never started, was closed, or crashed. Any subsequent context/session creation hits this RuntimeError.","triggerScenarios":"Calling crawler.arun() after __aexit__ closed the browser; reusing a crawler instance after its browser crashed (see 'Failed to start browser'); calling internal APIs before awaiting crawler.start(); using a manager whose cleanup() already ran.","commonSituations":"Reusing an AsyncWebCrawler outside its async with block; forgetting await crawler.start() when calling low-level strategy methods; background tasks racing with shutdown; browser process killed by OOM.","solutions":["Use the crawler inside its lifecycle: async with AsyncWebCrawler() as crawler: await crawler.arun(...) — it auto-starts.","If you manage lifecycle manually, await crawler.start() before use and don't call methods after close().","Create a fresh AsyncWebCrawler instance per batch instead of reusing a closed one.","Check earlier logs for the browser crash/stop reason (startup failure, OOM) and fix that first."],"exampleFix":"# before\ncrawler = AsyncWebCrawler()\nawait crawler.start()\nawait crawler.close()\nresults = await crawler.arun(url)  # RuntimeError: browser not available\n\n# after\nasync with AsyncWebCrawler() as crawler:\n    results = await crawler.arun(url)","handlingStrategy":"validation","validationCode":"if crawler.crawler_strategy.browser is None and not crawler.ready:\n    await crawler.start()  # or refuse to proceed","typeGuard":"async def is_crawler_ready(crawler) -> bool:\n    return bool(getattr(crawler, 'ready', False)) or (\n        getattr(crawler.crawler_strategy, 'browser', None) is not None\n    )","tryCatchPattern":"try:\n    results = await crawler.arun(url)\nexcept RuntimeError as e:\n    if 'Browser is not available' in str(e):\n        crawler = AsyncWebCrawler(config=browser_config)  # fresh instance\n        async with crawler:\n            results = await crawler.arun(url)\n    else:\n        raise","preventionTips":["Always use 'async with AsyncWebCrawler() as crawler' scoping.","Never call crawler methods after close().","Create a new instance per batch rather than resurrecting closed ones."],"tags":["browser-manager","lifecycle","webcrawler"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}