karatelabs/karate · warning

Page.navigate timed out, retrying

Error message

Page.navigate timed out, retrying ({}/{}): {}

What it means

Karate's CDP driver retries Page.navigate when the browser fails to answer within the CDP timeout, logging this warning between attempts. The message reports attempt progress ({}/{}), the retry budget, and the target URL. It is a warning, not a thrown error; a RuntimeException is only rethrown after the final attempt also times out.

Solutions

  1. Increase the CDP timeout (e.g. karate.configure('webdriverTimeout'/'timeout') or the driver timeout config) so navigation has more headroom.
  2. Retry the driver.get()/loadUrl call; transient attempts often succeed on the second try.
  3. Verify the target URL is reachable from the test host (curl it) and check DNS/proxy settings.
  4. Reduce load on the browser/CI runner (fewer parallel Chrome instances) and ensure adequate CPU/memory.

Example fix

// before
karate.configure('timeout', 10000);
// after
karate.configure('timeout', 30000); // more headroom for slow Page.navigate on loaded CI
Defensive patterns

Strategy: retry

Validate before calling

// check reachability before navigating
boolean ok = java.net.InetAddress.getByName("example.com").isReachable(3000);

Try / catch

try { driver.get(url); } catch (RuntimeException e) { if (e.getMessage().contains("CDP timeout for: Page.navigate")) { driver.get(url); } else { throw e; } }

Prevention

When it happens

Trigger: driver.loadUrl / driver.get(url) where the CDP Page.navigate command exceeds the CDP timeout, e.getMessage() contains 'CDP timeout for: Page.navigate', and attempt < navAttempts - 1 so a retry is still available.

Common situations: Slow or overloaded CI machines, remote/headless Chrome under load, very large pages or slow redirects, network latency to an external URL, or a CDP websocket momentarily stalled during navigation.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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

Appendix: source

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

        //      (element-not-found, waitUntil timeouts, value mismatches). A deliberate
        //      abort re-aborts on every attempt, so after the bounded retries we accept
        //      the retention (history.feature's 204 test still passes); a spurious
        //      abort commits on a retry and the scenario gets the document it asked for.
        // (A beforeunload prompt is auto-accepted in the dialog handler above, so the
        // timeout retry is for genuine transient timeouts, not the leave-page case.)
        int navAttempts = 3;
        CdpResponse navResponse = null;
        boolean aborted = false;
        for (int attempt = 0; attempt < navAttempts; attempt++) {
            try {
                navResponse = cdp.method("Page.navigate")
                        .param("url", url)
                        .send();
            } catch (RuntimeException e) {
                boolean transientNavTimeout = e.getMessage() != null
                        && e.getMessage().contains("CDP timeout for: Page.navigate");
                if (transientNavTimeout && attempt < navAttempts - 1) {
                    logger.warn("Page.navigate timed out, retrying ({}/{}): {}", attempt + 1, navAttempts - 1, url);
                    continue;
                }
                throw e;
            }
            aborted = "net::ERR_ABORTED".equals(navResponse.getResultAsString("errorText"));
            if (!aborted) {
                break; // committed, an error page under the same loader, or a normal response
            }
            if (attempt < navAttempts - 1) {
                logger.warn("Page.navigate returned ERR_ABORTED, retrying ({}/{}): {}", attempt + 1, navAttempts - 1, url);
                sleep(150); // let an in-flight/racing navigation (e.g. pooled-reset about:blank) settle
            }
        }

        // Every attempt aborted — a deliberate download / 204-205 / window.stop() that
        // retains the current document. The returned loader never commits, never fires
        // DOMContentLoaded, and a loader-bound wait for it could only end in a timeout,
        // so return with the page as-is (genuine load failures instead commit an error

View on GitHub (pinned to a22eb90246)