xtekky/gpt4free · error · RuntimeError

CDPSession is not connected

Error message

CDPSession is not connected

What it means

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.

Source

Thrown at g4f/requests/cdp.py:433

                        # Resolve any futures waiting for this event
                        if method in self._event_handlers:
                            for fut in self._event_handlers[method]:
                                if not fut.done():
                                    fut.set_result(params)
                            self._event_handlers[method].clear()

                        if method in self._event_queues:
                            for q in self._event_queues[method]:
                                q.put_nowait(params)
        except Exception as e:
            if not self._closing:
                logger.error(f"CDP receiver loop error: {e}")

    async def call(self, method: str, **params) -> dict:
        """Call a CDP method and wait for its result."""
        if not self.ws:
            raise RuntimeError("CDPSession is not connected")

        self.id_counter += 1
        req_id = self.id_counter

        fut = asyncio.get_running_loop().create_future()
        self._pending_requests[req_id] = fut

        payload = {"id": req_id, "method": method, "params": params}
        await self.ws.send_json(payload)

        try:
            return await asyncio.wait_for(fut, timeout=30.0)
        except asyncio.TimeoutError:
            raise TimeoutError(f"CDP call {method} timed out after 30 seconds")
        finally:
            self._pending_requests.pop(req_id, None)

    async def wait_for_event(self, method: str, timeout: float = 30.0) -> dict:

View on GitHub (pinned to 973504e177)

Solutions

  1. Ensure the session lifecycle is correct: await session.start() before any call, and stop issuing calls after close().
  2. Check `session.ws is not None` (or track a connected flag) before invoking call() from shared code paths.
  3. If another task may close concurrently, guard calls with an asyncio.Lock or check `session._closing`.
  4. Create a fresh CDPSession after a close instead of reusing the old object.

Example fix

// before
session = CDPSession()
await session.call("Page.enable")  # ws is None -> RuntimeError

// after
session = CDPSession()
await session.start()
try:
    await session.call("Page.enable")
finally:
    await session.close()
Defensive patterns

Strategy: type-guard

Validate before calling

if session.ws is None:
    raise RuntimeError("Connect the session first: await session.start()")

Type guard

def is_connected(session) -> bool:
    """True when the CDPSession has a live debugger socket."""
    return getattr(session, "ws", None) is not None and not getattr(session, "_closing", False)

Try / catch

try:
    result = await session.call(method, **params)
except RuntimeError as e:
    if "not connected" in str(e):
        session = CDPSession(); await session.start()  # reconnect and retry once
        result = await session.call(method, **params)
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of xtekky/gpt4free@973504e177 (2026-08-14). Data as JSON: /api/errors/e9203943614a68c7. Report an issue: GitHub.