karatelabs/karate · info
retry succeeded after
Error message
retry succeeded after {} attempt(s): eval {} What it means
This informational warning confirms that a transient-error retry loop for Runtime.evaluate succeeded on a non-first attempt: after 'attempt' failed tries (context not found, context destroyed, etc.), the CDP message finally succeeded. It is logged only when attempt > 0 and the response is not an error, and is purely diagnostic — no failure occurred. Its purpose is to make retry flakiness visible in CI logs.
Solutions
- No action needed on success — this is the retry mechanism working as designed.
- If it fires frequently for the same expression, add an explicit wait (waitFor/url transitions) before evaluating to reduce churn.
- Track frequency; a rising rate suggests environmental slowness or pages that swap contexts aggressively.
Defensive patterns
Strategy: retry
Prevention
- Add explicit waits before DOM reads to reduce retry churn
- Monitor warning frequency as a CI-health signal
- Stabilize pages that swap execution contexts aggressively
- Pin Chrome version in CI to reduce context-race variability
When it happens
Trigger: script()/eval where the evalRetry loop caught a transient CDP context error on earlier attempt(s), then message.send() returned a successful response.
Common situations: Evaluations racing navigation-driven context swaps, CI load delaying execution-context registration, tests reading DOM right after frame switches or redirects.
Related errors
- no frame at index: after retries
- javascript failed
- Page.navigate timed out, retrying
- Page.navigate returned ERR_ABORTED, retrying
- main-frame context not ready, retry
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/eb42f6396b25f3ee.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/driver/cdp/CdpDriver.java:1926
// Safety net only: the readiness future (getFrameContext awaits it)
// normally guarantees a live context here. A context can still die
// between the await and the send (e.g. a click triggered a navigation);
// the navigation's executionContextsCleared event invalidates the
// future, so the retry's getFrameContext() blocks for the replacement
// context on its own. We deliberately do NOT invalidate from here: a
// -32000 that is NOT a navigation would otherwise strand the future
// incomplete (no new executionContextCreated would ever arrive) and
// make every later eval wait out the full timeout.
logger.warn("transient context error, retry {}/{}: {}", attempt + 1, maxRetries, truncate(expression, 100));
sleep(transientInterval);
continue;
}
logger.warn("retry exhausted for transient context error: {}", truncate(expression, 100));
}
// Success or non-transient error
if (attempt > 0 && !response.isError()) {
logger.warn("retry succeeded after {} attempt(s): eval {}", attempt, truncate(expression, 50));
}
return response;
}
// Should not reach here, but return last response if somehow we do
throw new RuntimeException("eval retry logic error for: " + expression);
}
/**
* Check if a CDP response indicates a transient execution context error
* that should be retried.
*
* DESIGN NOTES:
* - CDP error code -32000 is a generic "server error" used for ALL execution context issues
* - Chrome uses this code for: context destroyed, context not found, target navigated, etc.
* - Rather than matching specific messages (which may vary by Chrome version), we retry
* all -32000 errors since they're all related to transient context state
* - This is more robust than Puppeteer's message-matching approach and handles edge casesView on GitHub (pinned to a22eb90246)