{"record":{"id":"dfbd33df757a50c6","repo":"browser-use/browser-use","slug":"cdp-method-method-r-did-not-respond-within-self","errorCode":null,"errorMessage":"CDP method {method!r} did not respond within {self._cdp_request_timeout_s:.0f}s. The browser may be unresponsive (silent WebSocket — container crashed or proxy lost upstream).","messagePattern":"CDP method (.+?) did not respond within (.+?)s\\. The browser may be unresponsive \\(silent WebSocket — container crashed or proxy lost upstream\\)\\.","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"error","filePath":"browser_use/browser/_cdp_timeout.py","lineNumber":122,"sourceCode":"\t) -> None:\n\t\tsuper().__init__(*args, **kwargs)\n\t\tself._cdp_request_timeout_s: float = _coerce_valid_timeout(cdp_request_timeout_s)\n\n\tasync def send_raw(\n\t\tself,\n\t\tmethod: str,\n\t\tparams: Any | None = None,\n\t\tsession_id: str | None = None,\n\t) -> dict[str, Any]:\n\t\ttry:\n\t\t\treturn await asyncio.wait_for(\n\t\t\t\tsuper().send_raw(method=method, params=params, session_id=session_id),\n\t\t\t\ttimeout=self._cdp_request_timeout_s,\n\t\t\t)\n\t\texcept TimeoutError as e:\n\t\t\t# Raise a plain TimeoutError so existing `except TimeoutError`\n\t\t\t# handlers in browser-use / tools treat this uniformly.\n\t\t\traise TimeoutError(\n\t\t\t\tf'CDP method {method!r} did not respond within {self._cdp_request_timeout_s:.0f}s. '\n\t\t\t\tf'The browser may be unresponsive (silent WebSocket — container crashed or proxy lost upstream).'\n\t\t\t) from e\n","sourceCodeStart":104,"sourceCodeEnd":126,"githubUrl":"https://github.com/browser-use/browser-use/blob/6c73fced2f6d45a11d88622fe56365a5fe18f28b/browser_use/browser/_cdp_timeout.py#L104-L126","documentation":"A CDPConnection wrapper enforces a per-request timeout (`_cdp_request_timeout_s`) around every raw CDP WebSocket send. When a method (e.g. Page.navigate, Runtime.evaluate) gets no response frame within the window, it raises TimeoutError with the method name and a hint: the WebSocket stayed open but silent, typical of a crashed browser container or a proxy that lost its upstream connection. It deliberately raises plain TimeoutError so existing handlers match uniformly.","triggerScenarios":"Any CDP operation while the browser process is hung or dead-but-socket-open: OOM-killed headless Chrome in Docker, a remote browser behind a proxy whose upstream dropped, frozen page due to GPU/render deadlock, or an extremely slow method exceeding the configured timeout.","commonSituations":"Long-running automation in containers where Chrome gets OOM-reaped; remote/CDP-URL setups (`cdp_url=`) through flaky proxies; heavy pages (infinite loops in JS) blocking the CDP response thread; timeouts surfacing after network changes mid-session.","solutions":["Treat it as a dead browser: tear down the session (`await browser.close()`) and recreate it, then retry the task — a hung CDP socket rarely recovers.","If genuinely slow operations are expected, raise `_cdp_request_timeout_s` on the CDP connection config.","For containers: add memory/CPU headroom or a Chrome watchdog to stop silent OOM kills.","For `cdp_url` setups: verify the proxy/upstream health independently before blaming the page."],"exampleFix":"# before\nstate = await agent.run()  # mid-run CDP hang surfaces as TimeoutError, run keeps waiting\n\n# after\nimport asyncio\nfrom browser_use import Agent, Browser\nasync def main():\n    try:\n        return await Agent(task=t, llm=llm, browser=Browser()).run(max_steps=20)\n    except TimeoutError:\n        await browser.close()  # kill dead session\n        return await Agent(task=t, llm=llm, browser=Browser()).run(max_steps=20)  # fresh retry","handlingStrategy":"retry","validationCode":"# Pre-flight: cheap CDP round-trip before launching a long task\nasync def cdp_alive(browser, timeout_s=10) -> bool:\n    try:\n        conn = await browser._get_cdp_connection() if hasattr(browser, '_get_cdp_connection') else None\n        if conn is None:\n            return True  # cannot probe; assume ok\n        await asyncio.wait_for(conn.send_raw('Browser.getVersion'), timeout=timeout_s)\n        return True\n    except TimeoutError:\n        return False","typeGuard":null,"tryCatchPattern":"async def run_resilient(task, llm, max_restarts=2):\n    for attempt in range(max_restarts + 1):\n        browser = Browser()\n        try:\n            agent = Agent(task=task, llm=llm, browser=browser)\n            return await agent.run()\n        except TimeoutError as e:\n            if 'CDP method' not in str(e) or attempt == max_restarts:\n                raise\n            logger.warning('CDP hang (%s); recreating browser', e)\n        finally:\n            await browser.close()","preventionTips":["Give containerized Chrome memory/CPU headroom and a supervisor that restarts it on OOM.","For `cdp_url` connections, monitor upstream health; a silent WebSocket means the far end died.","Wrap long tasks in a browser-recreate loop keyed on TimeoutError with 'CDP method' in the message."],"tags":["cdp","timeout","websocket","browser-crash","docker"],"backgroundTag":null,"analyzedSha":"6c73fced2f6d45a11d88622fe56365a5fe18f28b","analyzedAt":"2026-08-14T19:42:40.557Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}