flowable/flowable-engine · error · ActivitiIllegalArgumentException

Skip expression does not resolve to a boolean: ${skipExpress

Error message

Skip expression does not resolve to a boolean: ${skipExpression.getExpressionText()}

What it means

Thrown as ActivitiIllegalArgumentException from SkipExpressionUtil.shouldSkipFlowElement when the evaluated skipExpression does not return a Boolean. Skip expressions on service tasks etc. must resolve to true or false; any other result type causes the engine to fail the execution.

Source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/SkipExpressionUtil.java:48

        if (isSkipExpressionEnabled == null) {
            return false;

        } else if (isSkipExpressionEnabled instanceof Boolean) {
            return ((Boolean) isSkipExpressionEnabled).booleanValue();

        } else {
            throw new ActivitiIllegalArgumentException(skipExpressionEnabledVariable + " variable does not resolve to a boolean. " + isSkipExpressionEnabled);
        }
    }

    public static boolean shouldSkipFlowElement(DelegateExecution execution, Expression skipExpression) {
        Object value = skipExpression.getValue(execution);

        if (value instanceof Boolean) {
            return ((Boolean) value).booleanValue();

        } else {
            throw new ActivitiIllegalArgumentException("Skip expression does not resolve to a boolean: " + skipExpression.getExpressionText());
        }
    }
}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Rewrite the skip expression to return a strict boolean: ${var == 'expected'} instead of ${var}.
  2. Handle null in the expression: ${myVar != null && myVar.flag} or provide a default value for the variable.
  3. If the underlying value is a String "true"/"false", coerce it: ${Boolean.parseBoolean(myVar)}.
  4. Verify the referenced variable's type in the process instance before the activity executes.

Example fix

// before: evaluates to String
<activiti:skipExpression>${skipFlag}</activiti:skipExpression>

// after: guaranteed Boolean
<activiti:skipExpression>${Boolean.parseBoolean(skipFlag)}</activiti:skipExpression>
Defensive patterns

Strategy: validation

Validate before calling

// ensure the referenced variable is a Boolean before the skip-enabled activity runs
Object skipFlag = runtimeService.getVariable(executionId, "skipFlag");
if (!(skipFlag instanceof Boolean)) {
    throw new IllegalStateException("skipFlag must resolve to Boolean for the skip expression");
}

Type guard

boolean resolvesToBoolean(Expression expr, DelegateExecution execution) {
    try { return expr.getValue(execution) instanceof Boolean; }
    catch (Exception e) { return false; }
}

Try / catch

try {
    // run activity with skipExpression
    taskService.complete(taskId, vars);
} catch (ActivitiIllegalArgumentException e) {
    if (e.getMessage().startsWith("Skip expression does not resolve to a boolean")) {
        logger.error("Check skipExpression '{}' — it must return Boolean", exprText);
    }
    throw e;
}

Prevention

When it happens

Trigger: A flow element declares <activiti:skipExpression> whose expression evaluates to a non-Boolean value — e.g. "${condition}" where condition is a String, Integer, or null — and the element is executed with skip enabled.

Common situations: Expressions that compare values and accidentally return a String; expressions referencing a null variable (result is null, not Boolean); writing an expression like ${var1 + var2} producing a number; copy-pasting a condition used elsewhere as text.

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


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