karatelabs/karate · error · RuntimeException
assert expression must return boolean:
Error message
assert expression must return boolean:
What it means
Karate's 'assert' step requires its expression to evaluate to a boolean. If runtime.eval returns a non-Boolean (number, string, null, map), Karate throws this RuntimeException naming the offending expression, because the assertion result cannot be interpreted as pass/fail.
Solutions
- Wrap the expression in a comparison returning boolean: 'assert response.status != null'
- If checking existence, use a boolean operator (e.g. 'assert karate.sizeOf(list) > 0')
- Make helper functions return booleans, or compare their result explicitly
- Use karate.match / match steps instead of raw asserts for structural checks
Example fix
// before: expression is a value, not boolean assert response // after assert response != null && response.id != null
Defensive patterns
Strategy: type-guard
Validate before calling
// evaluate the expression and check its type before using assert semantics Object v = karate.eval(expression); boolean isBool = v instanceof Boolean;
Type guard
static boolean isBooleanResult(Object v) { return v instanceof Boolean; } Try / catch
try { executor.execute(assertStep); } catch (RuntimeException e) { if (e.getMessage().startsWith("assert expression must return boolean")) { throw new IllegalStateException("wrap expression in a comparison: " + e.getMessage()); } throw e; } Prevention
- Always assert comparisons, not bare values
- Make helper functions return booleans
- Prefer match steps for structural checks
When it happens
Trigger: An assert step whose expression yields a non-boolean value: 'assert response' (a map), 'assert someNumber', 'assert myString', or a function call returning a non-boolean.
Common situations: Assuming truthy/falsy JS semantics apply; asserting directly on response bodies or variables; calling a helper function that returns data instead of a comparison result.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- assert failed:
- multipart fields expects a map:
- multipart files expects a list or map:
- prettyXml() argument must be XML node or string
- append() needs at least two arguments
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/64fd473468713f01.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/core/StepExecutor.java:1905
/**
* True for an expression like {@code ({ a: 1 })} or {@code ([1, 2])} — a JSON literal
* the user forced through JS evaluation by wrapping it in round brackets.
*/
private static boolean isParenWrappedJson(String expr) {
if (expr.length() < 3 || expr.charAt(0) != '(' || expr.charAt(expr.length() - 1) != ')') {
return false;
}
return StringUtils.looksLikeJson(expr.substring(1, expr.length() - 1).trim());
}
private void executeAssert(Step step) {
Object result = runtime.eval(step.getText());
if (result instanceof Boolean b) {
if (!b) {
throw new AssertionError(withCommentLabel(step, "assert failed: " + step.getText()));
}
} else {
throw new RuntimeException("assert expression must return boolean: " + step.getText());
}
}
private static final LogContext.LogWriter SCENARIO_LOG = LogContext.with(LogContext.SCENARIO_LOGGER);
private void executePrint(Step step) {
// Wrap in array to handle comma-separated expressions like: print 'foo', 'bar'
// Without wrapping, JS comma operator would return only the last value
Object value = runtime.eval("[" + step.getText() + "]");
if (value instanceof List<?> list) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
if (i > 0) {
sb.append(' ');
}
sb.append(StepUtils.stringify(list.get(i)));
}
SCENARIO_LOG.info(sb.toString());View on GitHub (pinned to a22eb90246)