flowable/flowable-engine · error · FlowableException

condition expression returns null (elementId: " + elementId

Error message

condition expression returns null (elementId: " + elementId + ") for " + execution

What it means

Thrown by UelExpressionCondition.evaluate when a condition expression (e.g. a conditional sequence-flow ${...} expression) evaluates to null. The engine requires a definite Boolean verdict to route execution; null gives no routing information, so the engine fails fast instead of guessing a branch.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/el/UelExpressionCondition.java:40

 * {@link Condition} that resolves an UEL expression at runtime.
 * 
 * @author Joram Barrez
 * @author Frederik Heremans
 */
public class UelExpressionCondition implements Condition {

    protected Expression expression;

    public UelExpressionCondition(Expression expression) {
        this.expression = expression;
    }

    @Override
    public boolean evaluate(String elementId, DelegateExecution execution) {
        Object result = expression.getValue(execution);

        if (result == null) {
            throw new FlowableException("condition expression returns null (elementId: " + elementId + ") for " + execution);
        }
        if (!(result instanceof Boolean)) {
            throw new FlowableException("condition expression returns non-Boolean (elementId: " + elementId + "): " + result + " (" + result.getClass().getName() + ") for " + execution);
        }
        return (Boolean) result;
    }

}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Set the process variable referenced by the condition before execution reaches the conditional flow (runtimeService.setVariable(executionId, ...) or pass it at startProcessInstanceBy...).
  2. Make the condition null-safe, e.g. ${orderStatus != null && orderStatus == 'OK'}.
  3. Give the gateway a default flow so unset conditions route predictably (though the null verdict still throws - fixing the variable is required).
  4. Log/check which variable is missing: parse elementId from the message and inspect the process XML for the conditionExpression on that flow element.

Example fix

// before: expression references missing variable
<conditionExpression xsi:type="tFormalExpression">${order.status == 'APPROVED'}</conditionExpression>
// after: null-safe expression + guaranteed variable
<conditionExpression xsi:type="tFormalExpression">${order != null &amp;&amp; order.status == 'APPROVED'}</conditionExpression>
// and in Java: runtimeService.startProcessInstanceByKey("order", vars) with vars.put("order", order)
Defensive patterns

Strategy: validation

Validate before calling

// before starting/completing tasks that reach conditional flows
if (vars.get("orderStatus") == null) {
    throw new IllegalStateException("orderStatus must be set before gateway");
}

Type guard

Object v = execution.getVariable("orderStatus");
if (v instanceof String && ((String) v).isEmpty()) {
    throw new IllegalArgumentException("orderStatus empty");
}

Try / catch

try {
    taskService.complete(taskId, vars);
} catch (FlowableException e) {
    if (e.getMessage().contains("condition expression returns null")) {
        // set missing variable and retry
    }
}

Prevention

When it happens

Trigger: Calling evaluate(elementId, execution) where expression.getValue(execution) returns null. Typical API path: process runtime reaching an inclusive/exclusive gateway or conditional flow whose conditionExpression resolves to nothing - e.g. expression ${orderStatus == 'OK'} where variable orderStatus is unset (juel resolves to null), or an expression returning null explicitly.

Common situations: Process variables not set before the gateway (deployed process expects a variable the caller never passes); typos in variable names inside EL expressions; Spring/CDN bean lookups in expressions resolving to null; migrations where a variable was renamed; returning null from a delegateBean method used in the condition.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/8f8bde58b629558a. Report an issue: GitHub.