{"record":{"id":"5109e0aa12811c65","repo":"xtekky/gpt4free","slug":"timeout-waiting-for-event-method","errorCode":null,"errorMessage":"Timeout waiting for event {method}","messagePattern":"Timeout waiting for event (.+?)","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"warning","filePath":"g4f/requests/cdp.py","lineNumber":462,"sourceCode":"        try:\n            return await asyncio.wait_for(fut, timeout=30.0)\n        except asyncio.TimeoutError:\n            raise TimeoutError(f\"CDP call {method} timed out after 30 seconds\")\n        finally:\n            self._pending_requests.pop(req_id, None)\n\n    async def wait_for_event(self, method: str, timeout: float = 30.0) -> dict:\n        \"\"\"Wait for a specific CDP event to fire (one-time).\"\"\"\n        fut = asyncio.get_running_loop().create_future()\n        if method not in self._event_handlers:\n            self._event_handlers[method] = []\n        self._event_handlers[method].append(fut)\n\n        try:\n            return await asyncio.wait_for(fut, timeout=timeout)\n        except asyncio.TimeoutError:\n            self._event_handlers[method].remove(fut)\n            raise TimeoutError(f\"Timeout waiting for event {method}\")\n\n    def add_event_handler(self, method: str, queue: asyncio.Queue):\n        \"\"\"Add a persistent event listener that pushes events to an asyncio.Queue.\"\"\"\n        if method not in self._event_queues:\n            self._event_queues[method] = []\n        self._event_queues[method].append(queue)\n\n    def remove_event_handler(self, method: str, queue: asyncio.Queue):\n        \"\"\"Remove a persistent event listener.\"\"\"\n        if method in self._event_queues and queue in self._event_queues[method]:\n            self._event_queues[method].remove(queue)\n\n    async def evaluate_js(self, expression: str) -> Any:\n        \"\"\"Execute JavaScript and return the value.\"\"\"\n        res = await self.call(\n            \"Runtime.evaluate\", expression=expression, returnByValue=True\n        )\n        return res.get(\"result\", {}).get(\"value\")","sourceCodeStart":444,"sourceCodeEnd":480,"githubUrl":"https://github.com/xtekky/gpt4free/blob/973504e1770928ed5fb82f43da528f441ad9ddc3/g4f/requests/cdp.py#L444-L480","documentation":"Raised by CDPSession.wait_for_event() in g4f/requests/cdp.py when the awaited CDP event did not fire within `timeout` (default 30s). Unlike call(), this waits for browser-emitted events (e.g. Network.loadingFinished, Page.loadEventFired); the future is removed from the handler list on timeout so it does not leak. It means the expected lifecycle event never happened on the page.","triggerScenarios":"Waiting for Page.loadEventFired on a page whose load stalls (pending WebSocket, long-poll); waiting for a network event for a request that was served from cache or blocked; waiting for an event name that is disabled because its CDP domain was never enabled; the event fired before wait_for_event registered (race).","commonSituations":"Flaky third-party pages that never finish loading; ad-blockers or Chrome's cache suppressing the expected Network event; typos in CDP event method names; races where navigation completes before the waiter attaches.","solutions":["Increase the timeout argument where the page is known to be slow (e.g. wait_for_event(\"Page.loadEventFired\", timeout=120)).","Enable the relevant domain before waiting (Page.enable / Network.enable) — events only stream for enabled domains.","Double-check the exact CDP event name against the protocol docs (case-sensitive, e.g. 'Page.loadEventFired').","Attach the waiter before triggering the action that causes the event to avoid the race.","Fall back to polling (evaluate_js on document.readyState) when load events are unreliable."],"exampleFix":"// before\nawait session.navigate(url)\nawait session.wait_for_event(\"Page.loadEventFired\")  # attached too late / too short\n\n// after\ntask = asyncio.create_task(session.wait_for_event(\"Page.loadEventFired\", timeout=120))\nawait session.navigate(url)\nawait task","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    params = await session.wait_for_event(\"Page.loadEventFired\", timeout=60)\nexcept TimeoutError:\n    # fall back to polling readiness instead of failing\n    while (await session.evaluate_js(\"document.readyState\")) != \"complete\":\n        await asyncio.sleep(0.5)","preventionTips":["Register the event waiter before triggering the action that fires the event.","Enable the relevant CDP domain before waiting on its events.","Size timeouts to the slowest realistic page load; default is 30s."],"tags":["cdp","timeout","events","race-condition","lifecycle"],"backgroundTag":null,"analyzedSha":"973504e1770928ed5fb82f43da528f441ad9ddc3","analyzedAt":"2026-08-14T23:45:32.408Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}