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
- Usually ignorable — Karate falls back to lifecycle events for load detection
- If it precedes hangs, add explicit waitFor/Page.navigate guards and avoid navigating while a previous navigation is in flight
- 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
- Avoid rapid back-to-back navigations
- Use explicit waitFor on readyState instead of relying on implicit detection
- Keep the CDP websocket stable (no idle-proxies dropping it)
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
- page load timeout after
- page load complete but JS context not ready yet
- readyState check exception
- CDP connection failed readiness check
- CDP timeout for
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)