flowable/flowable-engine · error · org.activiti.engine.ActivitiException
condition script returns null
Error message
condition script returns null: ${expression} What it means
ScriptCondition.evaluate runs the condition expression through the ScriptingEngines for the configured language. If the script evaluates to null the condition cannot be interpreted as true/false, so an ActivitiException is thrown including the original expression text.
Solutions
- Ensure the condition script explicitly returns a boolean (add 'return' where the language requires it).
- Check the script's last statement actually produces a value rather than calling a void method.
- If using JavaScript, return explicit true/false instead of relying on truthy/falsy or undefined values.
- Verify the delegated bean/method used in the expression cannot return null.
Example fix
// before (Groovy condition)
${orderService.checkApproved(execution)} // void or null-returning
// after
${return orderService.isApproved(execution)} Defensive patterns
Strategy: validation
Validate before calling
// audit condition scripts before deployment
if (!conditionScript.matches("(?s).*\\breturn\\b.*")) {
throw new IllegalArgumentException("condition script must return a value: " + conditionScript);
} Try / catch
try {
conditionResult = ScriptCondition.evaluate(...);
} catch (ActivitiException e) {
if (e.getMessage().contains("returns null")) {
throw new InvalidConditionException("fix the script to return a boolean");
}
throw e;
} Prevention
- Always write condition scripts with an explicit 'return <boolean>' statement.
- Avoid void method calls as the last statement of a condition script.
- Unit-test sequence flow conditions before deploying the process.
When it happens
Trigger: A sequence-flow condition script (e.g. a Groovy/JS condition on a flow) whose last statement evaluates to null or has no return value — commonly a script that performs an action but never returns a value.
Common situations: Groovy/JavaScript scripts that forget 'return', scripts whose final expression is a void method call, dynamic language returning undefined (JS) instead of a boolean, condition script delegating to a bean method returning null.
Related errors
- condition script returns non-Boolean
- condition expression returns null
- condition script returns non-Boolean: () for
- condition script returns null: for
- Error code must not be null.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/458631eb788145d8.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/scripting/ScriptCondition.java:55
}
@Override
public boolean evaluate(String sequenceFlowId, DelegateExecution execution) {
String conditionExpression = null;
if (Context.getProcessEngineConfiguration().isEnableProcessDefinitionInfoCache()) {
ObjectNode elementProperties = Context.getBpmnOverrideElementProperties(sequenceFlowId, execution.getProcessDefinitionId());
conditionExpression = getActiveValue(expression, DynamicBpmnConstants.SEQUENCE_FLOW_CONDITION, elementProperties);
} else {
conditionExpression = expression;
}
ScriptingEngines scriptingEngines = Context
.getProcessEngineConfiguration()
.getScriptingEngines();
Object result = scriptingEngines.evaluate(conditionExpression, language, execution);
if (result == null) {
throw new ActivitiException("condition script returns null: " + expression);
}
if (!(result instanceof Boolean)) {
throw new ActivitiException("condition script returns non-Boolean: " + result + " (" + result.getClass().getName() + ")");
}
return (Boolean) result;
}
protected String getActiveValue(String originalValue, String propertyName, ObjectNode elementProperties) {
String activeValue = originalValue;
if (elementProperties != null) {
JsonNode overrideValueNode = elementProperties.get(propertyName);
if (overrideValueNode != null) {
if (overrideValueNode.isNull()) {
activeValue = null;
} else {
activeValue = overrideValueNode.asString();
}
}View on GitHub (pinned to d6d39ce1c6)