karatelabs/karate · info

readyState check failed

Error message

readyState check failed: {}

What it means

CdpDriver performs a best-effort readyState check (evaluating document.readyState to decide whether domContentEventFired already happened) and swallows any exception, logging this warning. The check is a safety net; failure means the load-detection fast path could not run and normal lifecycle events will be relied upon.

Solutions

  1. Usually ignorable — Karate falls back to lifecycle events for load detection
  2. If it precedes hangs, add explicit waitFor/Page.navigate guards and avoid navigating while a previous navigation is in flight
  3. Check that the websocket connection is stable (no proxy timeouts) if this appears frequently
Defensive patterns

Strategy: fallback

Try / catch

// driver-internal check; callers rely on load events
// wrap navigation with explicit wait:
driver.setUrl(url);
driver.waitUntil("document.readyState == 'complete'");

Prevention

When it happens

Trigger: The evaluate call for document.readyState throwing — websocket hiccup, navigation racing the check, or page context destroyed mid-check.

Common situations: Rapid navigations in a scenario (check runs while the execution context is being swapped); about:blank or detached frames lacking a document; CDP channel briefly busy after Page.navigate.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/15e8a2afed1b416c. Report an issue: GitHub.

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/driver/cdp/CdpDriver.java:819

     * Check if the current page is already loaded (document.readyState is 'complete' or 'interactive').
     * This handles the case where we connect to an already-loaded page or the event was missed.
     */
    private void checkIfPageAlreadyLoaded() {
        try {
            CdpResponse response = cdp.method("Runtime.evaluate")
                    .param("expression", "document.readyState")
                    .param("returnByValue", true)
                    .send();
            String readyState = response.getResultAsString("result.value");
            if ("complete".equals(readyState) || "interactive".equals(readyState)) {
                if (!domContentEventFired) {
                    logger.debug("page already loaded (readyState={}), setting domContentEventFired", readyState);
                    domContentEventFired = true;
                }
            }
        } catch (Exception e) {
            // Ignore - this is just a safety check
            logger.warn("readyState check failed: {}", e.getMessage());
        }
    }

    @SuppressWarnings("unchecked")
    private void setupEventHandlers() {
        // Listen to BOTH lifecycle events AND domContentEventFired for maximum compatibility
        // Page.lifecycleEvent is more reliable per-frame (Puppeteer approach)
        // Page.domContentEventFired is a fallback for environments where lifecycle events don't fire
        //
        // NOTE on session filtering: with OOPIF support, Page.enable is called on every isolated
        // iframe session, so those sessions also stream Page.* events into this client. Without
        // a sessionId filter, an OOPIF's DOMContentLoaded would flip the parent's domContentEventFired
        // prematurely, and an OOPIF's frameStartedLoading would leak its frameId into
        // framesStillLoading. Every Page.* handler that mutates parent state must reject events
        // whose sessionId is not the current page session.
        cdp.on("Page.lifecycleEvent", event -> {
            if (isFromOtherSession(event)) return;
            String name = event.get("name");

View on GitHub (pinned to a22eb90246)