{"record":{"id":"e9203943614a68c7","repo":"xtekky/gpt4free","slug":"cdpsession-is-not-connected","errorCode":null,"errorMessage":"CDPSession is not connected","messagePattern":"CDPSession is not connected","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"g4f/requests/cdp.py","lineNumber":433,"sourceCode":"\n                        # Resolve any futures waiting for this event\n                        if method in self._event_handlers:\n                            for fut in self._event_handlers[method]:\n                                if not fut.done():\n                                    fut.set_result(params)\n                            self._event_handlers[method].clear()\n\n                        if method in self._event_queues:\n                            for q in self._event_queues[method]:\n                                q.put_nowait(params)\n        except Exception as e:\n            if not self._closing:\n                logger.error(f\"CDP receiver loop error: {e}\")\n\n    async def call(self, method: str, **params) -> dict:\n        \"\"\"Call a CDP method and wait for its result.\"\"\"\n        if not self.ws:\n            raise RuntimeError(\"CDPSession is not connected\")\n\n        self.id_counter += 1\n        req_id = self.id_counter\n\n        fut = asyncio.get_running_loop().create_future()\n        self._pending_requests[req_id] = fut\n\n        payload = {\"id\": req_id, \"method\": method, \"params\": params}\n        await self.ws.send_json(payload)\n\n        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:","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/xtekky/gpt4free/blob/973504e1770928ed5fb82f43da528f441ad9ddc3/g4f/requests/cdp.py#L415-L451","documentation":"Raised by CDPSession.call() in g4f/requests/cdp.py when self.ws is falsy — i.e. a CDP command is issued before connect()/start() completed, or after close() tore down the WebSocket. The session object exists but has no live debugger socket, so any protocol call is refused immediately.","triggerScenarios":"Calling session.call(\"Page.navigate\", ...) without awaiting session.start() first; using the session inside an except/finally block after close() already ran; reusing a session whose receiver loop crashed and closed the socket.","commonSituations":"Missing await in asyncio code (start() never awaited); sharing one session across tasks where one task closes it while another still sends commands; forgetting that close() invalidates the object permanently.","solutions":["Ensure the session lifecycle is correct: await session.start() before any call, and stop issuing calls after close().","Check `session.ws is not None` (or track a connected flag) before invoking call() from shared code paths.","If another task may close concurrently, guard calls with an asyncio.Lock or check `session._closing`.","Create a fresh CDPSession after a close instead of reusing the old object."],"exampleFix":"// before\nsession = CDPSession()\nawait session.call(\"Page.enable\")  # ws is None -> RuntimeError\n\n// after\nsession = CDPSession()\nawait session.start()\ntry:\n    await session.call(\"Page.enable\")\nfinally:\n    await session.close()","handlingStrategy":"type-guard","validationCode":"if session.ws is None:\n    raise RuntimeError(\"Connect the session first: await session.start()\")","typeGuard":"def is_connected(session) -> bool:\n    \"\"\"True when the CDPSession has a live debugger socket.\"\"\"\n    return getattr(session, \"ws\", None) is not None and not getattr(session, \"_closing\", False)","tryCatchPattern":"try:\n    result = await session.call(method, **params)\nexcept RuntimeError as e:\n    if \"not connected\" in str(e):\n        session = CDPSession(); await session.start()  # reconnect and retry once\n        result = await session.call(method, **params)\n    else:\n        raise","preventionTips":["Always pair start()/close() with try/finally so the session is never used after teardown.","Check session.ws before calls in shared/multi-task code paths.","Never reuse a CDPSession after close(); create a fresh one."],"tags":["cdp","lifecycle","not-connected","asyncio","state-error"],"backgroundTag":null,"analyzedSha":"973504e1770928ed5fb82f43da528f441ad9ddc3","analyzedAt":"2026-08-14T23:45:32.408Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}