{"record":{"id":"1d24bbf9ff1a7474","repo":"karatelabs/karate","slug":"page-load-timeout-after-dms-url-s-strategy-s","errorCode":null,"errorMessage":"page load timeout after %dms - url: %s, strategy: %s, domContentEventFired: %s, framesStillLoading: %s, mainFrameId: %s, expectedLoaderId: %s, supersededLoaderId: %s, committedLoaderId: %s, domContentLoaderId: %s, readyState: %s, jsExec: %s, cdpOpen: %s","messagePattern":"page load timeout after (.+?)ms - url: (.+?), strategy: (.+?), domContentEventFired: (.+?), framesStillLoading: (.+?), mainFrameId: (.+?), expectedLoaderId: (.+?), supersededLoaderId: (.+?), committedLoaderId: (.+?), domContentLoaderId: (.+?), readyState: (.+?), jsExec: (.+?), cdpOpen: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/driver/cdp/CdpDriver.java","lineNumber":1440,"sourceCode":"            } catch (Exception e) {\n                // timeout (or exceptional completion): fall through and re-check\n            }\n        }\n\n        // Build diagnostic message with comprehensive state info\n        String url = pendingNavigationUrl != null ? pendingNavigationUrl : \"(unknown)\";\n        String readyStateInfo = getReadyStateForDiagnostic();\n        String jsExecInfo = getJsExecStateForDiagnostic();\n        String diagnostic = String.format(\n                \"page load timeout after %dms - url: %s, strategy: %s, \" +\n                \"domContentEventFired: %s, framesStillLoading: %s, mainFrameId: %s, \" +\n                \"expectedLoaderId: %s, supersededLoaderId: %s, committedLoaderId: %s, domContentLoaderId: %s, \" +\n                \"readyState: %s, jsExec: %s, cdpOpen: %s\",\n                timeout.toMillis(), url, strategy,\n                domContentEventFired, framesStillLoading, mainFrameId,\n                expectedLoaderId, supersededLoaderId, committedLoaderId, domContentLoaderId,\n                readyStateInfo, jsExecInfo, cdp.isOpen());\n        logger.warn(diagnostic);\n        throw new RuntimeException(diagnostic);\n    }\n\n    /**\n     * Verify that JS execution works in the context script() will actually use.\n     * <p>\n     * The page is only truly \"loaded\" once the main frame's default execution context\n     * is live - that is the single thing the readiness future tracks. We await it\n     * briefly (it is usually already complete; during a navigation swap it settles in\n     * milliseconds) and probe THAT context.\n     * <p>\n     * Crucially, an <i>error</i> from the explicit-context probe is NOT taken as \"JS not\n     * ready\": {@link #mainContextReady} can hand out a contextId that a loader\n     * replacement has already torn down when the matching executionContextsCleared was\n     * never delivered (routine under CI load). The stale id then errors forever and, on\n     * a fully-loaded page, wedges waitForPageLoad() to a 30s timeout — observed in CI as\n     * \"page load complete but JS context not ready yet\" while the timeout diagnostic\n     * reports {@code jsExec: ok} (it probes the default context). So on an explicit-","sourceCodeStart":1422,"sourceCodeEnd":1458,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/driver/cdp/CdpDriver.java#L1422-L1458","documentation":"This is the page-load timeout failure: waitForPageLoad exceeded its timeout budget, and the driver throws a RuntimeException carrying a rich diagnostic string (loader IDs, framesStillLoading, readyState, jsExec, cdpOpen). It means DOMContentLoaded/load never completed to the driver's satisfaction within the configured timeout for the given navigation strategy.","triggerScenarios":"driver.get()/loadUrl() where, after timeout.toMillis(), the condition (domContentEventFired + no frames still loading + verified JS execution for the strategy) is not met; e.g. domContentEventFired=false, framesStillLoading non-empty, or jsExec=false.","commonSituations":"Slow external resources (ads, fonts, analytics) blocking load events, an iframe that never stops loading, page-load timeout configured too low for CI, hung websocket (cdpOpen=false indicates the CDP connection died), or JS context never registering.","solutions":["Increase the page-load timeout configuration to cover slow pages/CI.","Use a lighter wait strategy if full load is unnecessary (e.g. wait until DOMContentLoaded rather than full load).","Block or stub slow third-party resources; check framesStillLoading in the diagnostic to find the offending frame.","If cdpOpen=false in the diagnostic, the browser/websocket crashed — check browser logs and increase browser/memory resources.","Navigate directly to the failing URL in a manual browser to identify what never finishes loading."],"exampleFix":"// before\nkarate.configure('timeout', 10000); // slow iframe exceeds budget\n// after\nkarate.configure('timeout', 45000); // and inspect framesStillLoading in the diagnostic for the culprit frame","handlingStrategy":"retry","validationCode":"// pre-check that the URL serves a document quickly\nvar resp = karate.http(url).get(); karate.log('status:', resp.status, 'time:', resp.time);","typeGuard":null,"tryCatchPattern":"try { driver.get(url); } catch (RuntimeException e) { if (e.getMessage().startsWith(\"page load timeout\")) { karate.log(e.getMessage()); /* parse framesStillLoading/jsExec for diagnosis */ } else { throw e; } }","preventionTips":["Set realistic page-load timeouts for CI hardware","Block/stub slow third-party resources","Inspect the diagnostic's framesStillLoading to find never-ending frames","Watch cdpOpen in the diagnostic for browser crashes; ensure adequate memory"],"tags":["cdp","page-load-timeout","navigation","diagnostics"],"backgroundTag":"request-timeout","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}