flowable/flowable-engine · error · FlowableException
condition expression returns non-Boolean
Error message
condition expression returns non-Boolean: <result> (<class name>)
What it means
RuleExpressionCondition.evaluate requires the input condition expression to produce a Boolean so the rule engine can compare it against the input entry. If the JUEL expression returns any non-Boolean value (String, Integer, etc.), Flowable throws this exception including the value and its class name. The decision table author must make the condition expression a comparison/logical expression.
Solutions
- Rewrite the input expression as a Boolean comparison, e.g. ${amount > 100} instead of ${amount}.
- Check that any custom EL function used in the condition returns Boolean, not String/Number.
- If the expression evaluates a String, wrap it in a comparison or a Boolean-returning helper function.
- Validate the exported DMN XML: inputExpression expressionLanguage JUEL entries should end in boolean predicates.
- Log result.getClass() at the call site to identify which expression returns the wrong type (the message already embeds value + class name).
Example fix
// before (DMN input expression)
${customerLevel} // returns String "gold"
// after
${customerLevel == 'gold'} // returns Boolean Defensive patterns
Strategy: type-guard
Validate before calling
Object v = evaluateRaw(expr); if (!(v instanceof Boolean)) throw new IllegalStateException("condition not boolean: " + v.getClass()); Type guard
boolean conditionYieldsBoolean(Object result) {
return result != null && result instanceof Boolean;
} Try / catch
try {
Boolean hit = condition.evaluate(container);
} catch (FlowableException e) {
if (e.getMessage().startsWith("condition expression returns non-Boolean")) {
log.error("Fix DMN input expression: {}", e.getMessage());
}
} Prevention
- Author input expressions as comparisons (x == 'gold'), never bare variables.
- Ensure custom EL functions return Boolean.
- Review DMN XML exports for non-predicate expressions.
- Test each decision table rule with representative variables.
- Log the embedded value/class from the message to locate the offending expression.
When it happens
Trigger: executeInputExpression calls evaluate and the expression returns e.g. a String ('yes'), an Integer, or a bare variable reference like ${customerLevel} instead of a comparison like ${customerLevel == 'gold'}.
Common situations: Decision table input expression written as a bare variable or literal rather than a boolean comparison; EL function returning a non-Boolean; spreadsheet/DMN export producing expressions of the wrong shape.
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
- condition expression returns null
- Could not create conclusion result
- Could not create execution variable
- Could not resolve loopCardinality expression
- decisionTableReferenceKey expression does not resolve to a…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/a6821a84c6941fe9.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/el/RuleExpressionCondition.java:48
protected Expression expression;
public RuleExpressionCondition(Expression expression) {
this.expression = expression;
}
public boolean evaluate(Map<String, Object> variables, ELExecutionContext executionContext) {
VariableContainerWrapper variableContainer = new VariableContainerWrapper(variables);
variableContainer.setInstanceId(executionContext.getInstanceId());
variableContainer.setScopeType(executionContext.getScopeType());
variableContainer.setTenantId(executionContext.getTenantId());
Object result = expression.getValue(variableContainer);
if (result == null) {
throw new FlowableException("condition expression returns null");
}
if (!(result instanceof Boolean)) {
throw new FlowableException("condition expression returns non-Boolean: " + result + " (" + result.getClass().getName() + ")");
}
return (Boolean) result;
}
}
View on GitHub (pinned to d6d39ce1c6)