xtekky/gpt4free · warning · TimeoutError

Timeout waiting for event

Error message

Timeout waiting for event {method}

What it means

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.

Solutions

  1. Increase the timeout argument where the page is known to be slow (e.g. wait_for_event("Page.loadEventFired", timeout=120)).
  2. Enable the relevant domain before waiting (Page.enable / Network.enable) — events only stream for enabled domains.
  3. Double-check the exact CDP event name against the protocol docs (case-sensitive, e.g. 'Page.loadEventFired').
  4. Attach the waiter before triggering the action that causes the event to avoid the race.
  5. Fall back to polling (evaluate_js on document.readyState) when load events are unreliable.

Example fix

// before
await session.navigate(url)
await session.wait_for_event("Page.loadEventFired")  # attached too late / too short

// after
task = asyncio.create_task(session.wait_for_event("Page.loadEventFired", timeout=120))
await session.navigate(url)
await task
Defensive patterns

Strategy: fallback

Try / catch

try:
    params = await session.wait_for_event("Page.loadEventFired", timeout=60)
except TimeoutError:
    # fall back to polling readiness instead of failing
    while (await session.evaluate_js("document.readyState")) != "complete":
        await asyncio.sleep(0.5)

Prevention

When it happens

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

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

Understand the failure class

Related errors


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

Appendix: source

Thrown at g4f/requests/cdp.py:462

        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:
        """Wait for a specific CDP event to fire (one-time)."""
        fut = asyncio.get_running_loop().create_future()
        if method not in self._event_handlers:
            self._event_handlers[method] = []
        self._event_handlers[method].append(fut)

        try:
            return await asyncio.wait_for(fut, timeout=timeout)
        except asyncio.TimeoutError:
            self._event_handlers[method].remove(fut)
            raise TimeoutError(f"Timeout waiting for event {method}")

    def add_event_handler(self, method: str, queue: asyncio.Queue):
        """Add a persistent event listener that pushes events to an asyncio.Queue."""
        if method not in self._event_queues:
            self._event_queues[method] = []
        self._event_queues[method].append(queue)

    def remove_event_handler(self, method: str, queue: asyncio.Queue):
        """Remove a persistent event listener."""
        if method in self._event_queues and queue in self._event_queues[method]:
            self._event_queues[method].remove(queue)

    async def evaluate_js(self, expression: str) -> Any:
        """Execute JavaScript and return the value."""
        res = await self.call(
            "Runtime.evaluate", expression=expression, returnByValue=True
        )
        return res.get("result", {}).get("value")

View on GitHub (pinned to 973504e177)