karatelabs/karate · warning

readyState check exception

Error message

readyState check exception: {}

What it means

The readyState probe (used during page-load waits) wraps any exception and logs this warning before returning false. A 'websocket not open' message is demoted to trace level; anything else — e.g. an evaluation error because the execution context was destroyed mid-navigation — is logged at warn. The wait loop treats it as 'not ready yet' and keeps polling, so this is non-fatal by itself.

Solutions

  1. If the load then completes, no action is needed — the probe recovered.
  2. If cdpOpen=false and the wait times out, the browser/websocket died: check browser crash logs and resources.
  3. Retry the navigation; transient context churn usually settles.
  4. Ensure the page isn't navigating itself (redirect loops) that keeps destroying contexts.
Defensive patterns

Strategy: retry

Validate before calling

// verify the browser connection is alive before heavy navigation work
boolean open = driver.driverOptions != null; // use driver health/config checks available in your harness

Prevention

When it happens

Trigger: The periodic readyState evaluation during driver.get()/loadUrl() throws — typically a Runtime exception from script evaluation on a context destroyed by navigation, or a websocket send after the CDP connection dropped.

Common situations: Navigation swapping execution contexts while the probe runs, browser tab closed/crashed mid-load (websocket gone), or CI races during frame detach.

Related errors


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

Appendix: source

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

                    .send();
            if (response.isError()) {
                // Log the error so we can diagnose CI failures
                logger.warn("readyState check CDP error: {}", response.getErrorMessage());
                return false;
            }
            String readyState = response.getResultAsString("result.value.r");
            logger.trace("readyState check returned: {}", readyState); // keep trace, this is success path
            boolean ready = "complete".equals(readyState) || "interactive".equals(readyState);
            if (ready && requireUrl != null) {
                ready = urlsEquivalent(requireUrl, response.getResultAsString("result.value.u"));
            }
            return ready;
        } catch (Exception e) {
            String msg = e.getMessage();
            if (msg != null && msg.contains("websocket not open")) {
                logger.trace("readyState check skipped: websocket not open");
            } else {
                logger.warn("readyState check exception: {}", msg);
            }
            return false;
        }
    }

    /**
     * Whether a requested navigation/history URL and the document's live
     * {@code location.href} name the same resource, tolerating a lone trailing-slash
     * difference (a request for {@code …/path} commonly settles as {@code …/path/}).
     * Exact otherwise — this gates accepting a readyState=complete read as the target
     * document, so it must not treat genuinely different URLs as equal.
     */
    static boolean urlsEquivalent(String requested, String actual) {
        if (requested == null || actual == null) {
            return false;
        }
        if (requested.equals(actual)) {
            return true;

View on GitHub (pinned to a22eb90246)