karatelabs/karate · warning

page load complete but JS context not ready yet

Error message

page load complete but JS context not ready yet

What it means

During waitForPageLoad, the driver's load-complete condition requires not only page-load events but also a working JS execution context. This warning is logged when page load events (DOMContentLoaded/load) fired but verifyJsExecution() still fails, meaning script() cannot yet execute in the context. The wait loop keeps polling rather than returning, so the caller experiences a delayed return or, if the context never becomes ready, the eventual page-load timeout (error 844).

Solutions

  1. Increase the page-load timeout to give the execution context time to register.
  2. Retry the navigation; the race usually resolves on a second attempt.
  3. Update Chrome/Chromium — older builds emit context events late under load.
  4. If persistent, log window performance and reduce page JS (extensions, analytics) slowing context creation.

Example fix

// before
karate.configure('timeout', 15000); // context probe races load event
// after
karate.configure('timeout', 30000); // allow execution context to register after load events
Defensive patterns

Strategy: retry

Try / catch

try { driver.get(url); } catch (RuntimeException e) { if (e.getMessage().contains("page load timeout")) { driver.get(url); } else { throw e; } }

Prevention

When it happens

Trigger: driver.get()/loadUrl() where domContentEventFired is true but verifyJsExecution() (a probe script via the context script() will use) throws or returns nothing yet.

Common situations: Fast page-load events racing execution-context creation in headless Chrome, heavy page JS delaying context readiness, or CI environments where frame/context events arrive out of order.

Related errors


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

Appendix: source

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

     */
    public void waitForPageLoad(PageLoadStrategy strategy, Duration timeout) {
        long deadline = System.currentTimeMillis() + timeout.toMillis();
        long lastStaleCheck = 0;

        while (true) {
            // Snapshot the wake-up latch BEFORE evaluating conditions: an event
            // landing between the check below and the wait completes THIS snapshot,
            // so the signal cannot be lost (see nudgeLoadWaiter).
            CompletableFuture<Void> tick = loadTick;

            if (isPageLoadComplete(strategy)) {
                // Verify JS execution works (execution context is ready)
                // This handles the case where page events fired but context isn't ready
                if (verifyJsExecution()) {
                    return;
                }
                // Context not ready yet, keep waiting
                logger.warn("page load complete but JS context not ready yet");
            } else if (domContentEventFired && !framesStillLoading.isEmpty()) {
                // DOM is ready but frames appear to still be loading
                // Periodically verify these frames still exist - frameStoppedLoading
                // event can be lost in CI environments (observed as flaky timeout)
                long now = System.currentTimeMillis();
                if (now - lastStaleCheck > 2000) {
                    lastStaleCheck = now;
                    pruneStaleFrames();
                }
            }

            long remaining = deadline - System.currentTimeMillis();
            if (remaining <= 0 || Thread.currentThread().isInterrupted()) {
                break;
            }
            // Event-driven wait with a CAP, not a pure future wait: the conditions
            // above include polling fallbacks (document.readyState, pruneStaleFrames)
            // that exist precisely because load events get lost under CI load — a

View on GitHub (pinned to a22eb90246)