karatelabs/karate · error · DriverException
waitUntil timeout: expression
Error message
waitUntil timeout: ${locator} expression: ${expression} What it means
W3cDriver.waitUntil(locator, expression) repeatedly evaluates a JS expression scoped to the element, swallowing per-poll exceptions since the element may not exist yet. If the expression never returns truthy within the timeout, a DriverException naming the locator and expression is thrown.
Solutions
- Run the expression manually in browser devtools against the element to verify it can return truthy
- Increase the timeout via waitUntil(locator, expression, timeout)
- Fix the expression syntax/reference (it is evaluated as JavaScript in the page)
- Switch context (iframe/shadow) if the element is not in the main document
Example fix
// before
driver.waitUntil('.progress', "_.classList.contains('done')"); // never gets 'done'
// after
driver.waitUntil('.progress', "_.classList.contains('done')", 30000); // plus verify app applies the class Defensive patterns
Strategy: validation
Validate before calling
// sanity-check the expression once before polling Object v = driver.script(locator, expression); // or eval manually in devtools
Try / catch
try {
driver.waitUntil(locator, expression, timeout);
} catch (DriverException e) {
// expression never truthy; re-evaluate once and log the actual value
} Prevention
- Test the JS expression in devtools console first — poll exceptions are swallowed
- Ensure the element is reachable from the main document (iframe/shadow)
- Use boolean-returning expressions
When it happens
Trigger: Calling driver.waitUntil(locator, jsExpression) where the element never appears, or the expression keeps evaluating falsy (e.g. checking a class/style/state that never changes) within the timeout.
Common situations: JS expression has a typo or returns a non-boolean that is falsy; waiting for a CSS class the app never applies; element inside iframe/shadow DOM so the scoped lookup fails every poll; slow async update exceeding timeout.
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.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- waitUntil timeout
- waitFor timeout
- waitForAny timeout
- waitForText timeout: expected
- waitForEnabled timeout
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/85f9fe38b8122e90.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/driver/w3c/W3cDriver.java:637
return waitUntil(locator, expression, options.getTimeoutDuration());
}
@Override
public Element waitUntil(String locator, String expression, java.time.Duration timeout) {
long deadline = System.currentTimeMillis() + timeout.toMillis();
String js = Locators.scriptSelector(locator, expression);
while (System.currentTimeMillis() < deadline) {
try {
Object result = eval(js);
if (isTruthy(result)) {
return BaseElement.existing(this, locator);
}
} catch (Exception e) {
// Element may not exist yet
}
sleep(options.getRetryInterval());
}
throw new DriverException("waitUntil timeout: " + locator + " expression: " + expression);
}
@Override
public boolean waitUntil(String expression) {
return waitUntil(expression, options.getTimeoutDuration());
}
@Override
public boolean waitUntil(String expression, java.time.Duration timeout) {
long deadline = System.currentTimeMillis() + timeout.toMillis();
while (System.currentTimeMillis() < deadline) {
try {
Object result = eval(expression);
if (isTruthy(result)) {
return true;
}
} catch (Exception e) {
// IgnoreView on GitHub (pinned to a22eb90246)