karatelabs/karate · error · DriverException
element not found after
Error message
element not found after ${retryCount} retries: ${locator} | ${driverState} What it means
Before element operations, CdpDriver.retryIfNeeded() polls exists(locator) using the configured retry count and interval. If the element still does not exist after options.getRetryCount() attempts, it throws with the locator and a getDriverState() snapshot for diagnostics.
Solutions
- Verify the selector in the browser DevTools against the page state at that step.
- Increase options.retryCount / retryInterval in driver config for slow environments.
- Wait for prerequisite actions/navigation before the element call, or use driver.waitFor(locator, timeout) for an explicit budget.
- Switch to the correct frame first if the element lives in an iframe; inspect the driver-state suffix in the message for the current URL/frame.
Example fix
// before
DriverOptions options = new DriverOptions(); // default retries too low on slow CI
// after
options.setRetryCount(20);
options.setRetryInterval(500);
driver.waitFor('#slow-widget', Duration.ofSeconds(10));
driver.click('#slow-widget'); Defensive patterns
Strategy: retry
Validate before calling
// pre-check existence with your own budget before element ops
long deadline = System.currentTimeMillis() + 10_000;
while (!driver.exists(locator) && System.currentTimeMillis() < deadline) sleep(250);
if (!driver.exists(locator)) throw new IllegalStateException("not present: " + locator); Try / catch
try {
driver.click(locator);
} catch (Exception e) {
if (e.getMessage().contains("element not found after")) {
// driver state in message shows current URL/frame for triage
throw new AssertionError("element never appeared: " + e.getMessage(), e);
} else throw e;
} Prevention
- Raise retryCount/retryInterval for slow environments.
- waitFor elements explicitly instead of relying on implicit retries.
- Switch frames before interacting with iframe content.
- Keep selectors updated with the app's stable test ids.
When it happens
Trigger: Any element API (click, input, text, inputFile, select...) called with a locator that never matches during the retry window: wrong selector, element in an unswitched frame, element removed before the call, or retry budget too short for slow pages.
Common situations: Slow CI machines exceeding the default retry timeout; dynamic content rendered only after an async API call; iframe not switched; typo or changed id/class after an app update; SPA navigation clearing the element between steps.
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
- element vanished during action after
- timeout waiting for element
- Element not found
- retry FAILED after attempts: |
- retry failed after attempts:
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/853dc0baba39ada7.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/driver/cdp/CdpDriver.java:3221
@SuppressWarnings("unchecked")
public List<Object> scriptAll(String locator, Object expression) {
retryIfNeeded(locator);
String js = Locators.scriptAllSelector(locator, expression);
return (List<Object>) script(js);
}
// ========== Auto-Wait Helper ==========
/**
* Auto-wait for element to exist before operations.
* Uses retryCount and retryInterval from options.
* This is called automatically before element operations to reduce flaky tests.
*/
private void retryIfNeeded(String locator) {
boolean found = retry("element: " + locator, () -> exists(locator));
if (!found) {
// Include driver state in exception for better diagnostics
throw new DriverException("element not found after " + options.getRetryCount() +
" retries: " + locator + " | " + getDriverState());
}
}
/**
* Re-resolve attempts for an element that vanished between the existence check and
* the action eval. Small on purpose: each attempt already carries a full
* {@link #retryIfNeeded} poll, and a locator that keeps vanishing is a genuinely
* unstable page, not a transient worth papering over.
*/
private static final int ELEMENT_ACTION_ATTEMPTS = 3;
/**
* Wait for {@code locator} to exist, then run an action script that re-resolves it
* inside the page, retrying if it vanished in between.
* <p>
* The locator is resolved twice — once here by {@link #retryIfNeeded} (existence)
* and again by the action JS itself — so a document that swaps between the two evalsView on GitHub (pinned to a22eb90246)