karatelabs/karate · warning
main-frame context not ready, retry
Error message
main-frame context not ready, retry {}/{}: {} What it means
When evaluating an expression, the driver resolves the main frame's execution context via getFrameContext(); a slow context swap can make it return null, which would surface as a misleading null result. Instead of failing, the driver retries, logging this warning with the retry counter and a truncated expression, sleeping a short interval between attempts so the replacement executionContextCreated event can arrive.
Solutions
- No action usually needed — the retry loop self-heals once the context registers.
- If the fallback (error 848) follows, add a short retry/wait in the test before evaluating right after navigation or frame switch.
- Increase the transient retry interval/max retries via driver config if CI is chronically slow.
- Update Chrome; late executionContextCreated events under load are a known flake source.
Example fix
// before
string val = driver.script("window.mainValue"); // immediately after frame switch, context still swapping
// after
karate.waitFor(200); // or retry: let the replacement execution context register before evaluating
string val = driver.script("window.mainValue"); Defensive patterns
Strategy: retry
Prevention
- Wait briefly after frame switches/navigation before evaluating JS
- Increase driver retry interval/count for slow CI
- Update Chrome to reduce late executionContextCreated events
- Avoid evaluating on pooled drivers immediately after reset
When it happens
Trigger: script()/eval on the main frame where getFrameContext() returns null (context not yet registered) for attempts < maxRetries, e.g. right after a navigation swapped the main-frame execution context.
Common situations: 'Multiple switches' style tests reading window state immediately after frame switches under slow CI, evaluations racing a navigation's context replacement, pooled drivers resetting about:blank.
Related errors
- no frame at index: after retries
- Page.navigate timed out, retrying
- Page.navigate returned ERR_ABORTED, retrying
- page load complete but JS context not ready yet
- pruned stale frame(s) from framesStillLoading, remaining
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/3922acf700af7e7f.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/driver/cdp/CdpDriver.java:1872
// Use explicit context ID for reliable frame targeting (see getFrameContext notes)
Integer contextId = getFrameContext();
// We INTEND to run in the main frame but its execution context is not
// confirmed live (currentFrame == null && getFrameContext() == null). This
// is distinct from the OOPIF null (currentFrame != null) and the same-origin
// child-frame null, both of which legitimately fall through to the default
// context below.
boolean mainContextUnresolved = currentFrame == null && contextId == null;
if (mainContextUnresolved && attempt < maxRetries) {
// Do NOT silently fall back to CDP's ambient default context here. Right
// after a switchFrame(null), the ambient default can still resolve to the
// child frame we just left, so the script runs in the wrong world and
// returns a misleading null instead of the main-frame value - the source
// of a rare CI flake (frame.feature "Multiple switches" reading
// window.mainValue as null under a slow context swap). Self-heal instead:
// give the replacement executionContextCreated more time via the retry
// loop, which re-awaits the readiness future on the next getFrameContext().
// Logged at WARN so a recurrence is visible in CI for the next investigation.
logger.warn("main-frame context not ready, retry {}/{}: {}", attempt + 1, maxRetries, truncate(expression, 100));
sleep(transientInterval);
continue;
}
if (contextId != null) {
message.param("contextId", contextId);
} else if (mainContextUnresolved) {
// Retries exhausted and the main context never registered - e.g. a
// download / 204 / aborted navigation that clears the context without a
// replacement. Degrade to CDP's default context as a last resort rather
// than hard-failing, matching the documented graceful-degradation intent,
// but log loudly so a recurrence stands out in CI logs.
logger.warn("main-frame context never became ready after {} attempts, falling back to default context: {}", maxRetries, truncate(expression, 100));
}
CdpResponse response;
try {
response = message.send();
} catch (DialogOpenedException e) {View on GitHub (pinned to a22eb90246)