karatelabs/karate · warning
retry condition evaluation failed
Error message
retry condition evaluation failed: {} What it means
Karate evaluates a @retry-until condition by evaluating an expression via the runtime script engine. If the expression fails to evaluate (syntax error, undefined variable, non-boolean result), Karate logs this warning, treats the condition as not met, and continues retrying instead of failing the step. The message interpolates only e.getMessage(), which can be unhelpfully terse (e.g. '{}').
Solutions
- Fix the retry expression so it evaluates to a JS boolean and only references variables that exist at evaluation time
- Check the adjacent log line for e.getMessage(); reproduce the expression in a * print statement to see the actual engine error
- Guard the expression against missing data, e.g. retry-until responseStatus == 200 && response.foo != undefined && response.foo == 'x'
- If the condition should stop retries on error, implement a custom loop with * configure retry = ... or manual JS with karate.call for clearer diagnostics
Example fix
// before
* configure retry = { count: 5, interval: 2000 }
* get /items
* retry until response.data.status == 'DONE'
// after (guard against undefined so evaluation never throws)
* configure retry = { count: 5, interval: 2000 }
* get /items
* retry until responseStatus == 200 && response.data && response.data.status == 'DONE' Defensive patterns
Strategy: validation
Validate before calling
// before relying on retry, smoke-test the expression in the same feature
* def __retryOk =
"""
(function(){ try { return !! (response.data && response.data.status == 'DONE'); }
catch(e){ karate.log('retry expr error: ' + e); return false; } })()
""" Type guard
function safeRetryExpr(fn){ try { return !!fn(); } catch (e) { karate.log('retry expr failed: ' + e); return false; } } Prevention
- Only reference variables guaranteed to exist before retry starts (responseStatus, response)
- Guard nested fields with undefined checks in the retry expression
- Keep retry expressions to plain JS booleans; avoid calls into helpers that can throw
- Reproduce the expression with * print / karate.log to see engine errors directly
When it happens
Trigger: A scenario uses retry-until / configure retry with an expression that throws when evaluated: referencing an undefined variable, a syntax error, calling a method that throws, or the expression returning null/non-Boolean so TRUE.equals fails logically (though that path does not warn).
Common situations: Typo in a response-scoped variable before the first request runs; JSON path or JS syntax errors in the retry expression; a helper function not yet defined when retry starts; copy-pasted expressions from another dialect (e.g. Groovy/Python).
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- javascript failed
- Unable to resolve global `this`
- Invalid ignore
- karate-boot.js evaluation failed
- Dynamic expression must return a list or function
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/0e1115c5c5773b00.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/core/StepExecutor.java:2382
// Request skipped by listener
response = HttpResponse.skipped(request);
}
// Fire HTTP_EXIT event (always, even for skipped)
if (suite != null) {
suite.fireEvent(HttpRunEvent.exit(response.getRequest(), response, runtime));
}
// Set response variables so the condition can access them
setResponseVariables(response);
// Evaluate retry condition
boolean conditionMet;
try {
Object result = runtime.eval(retryUntil);
conditionMet = Boolean.TRUE.equals(result);
} catch (Exception e) {
logger.warn("retry condition evaluation failed: {}", e.getMessage());
conditionMet = false;
}
if (conditionMet) {
if (retryCount > 0) {
logger.debug("retry condition satisfied after {} attempts", retryCount + 1);
}
return response;
} else {
logger.debug("retry condition not satisfied: {}", retryUntil);
}
// Restore request state for next retry (http().invoke() resets it)
http().restoreFrom(httpCopy);
retryCount++;
}
}View on GitHub (pinned to a22eb90246)