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

  1. No action usually needed — the retry loop self-heals once the context registers.
  2. If the fallback (error 848) follows, add a short retry/wait in the test before evaluating right after navigation or frame switch.
  3. Increase the transient retry interval/max retries via driver config if CI is chronically slow.
  4. 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

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


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)