flowable/flowable-engine · error · FlowableIllegalArgumentException

Could not resolve loopCardinality expression '${loopCardinal

Error message

Could not resolve loopCardinality expression '${loopCardinalityExpression.getExpressionText()}': not a number nor number String

What it means

Thrown when parsing the loopCardinality of a multi-instance activity: the loopCardinalityExpression evaluated to a value that is neither a Number nor a String parsable as an integer, so resolveNumberOfInstances cannot compute the instance count. The message includes the expression text so you can identify the failing condition.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/MultiInstanceActivityBehavior.java:573

    protected boolean usesCollection() {
        return collectionExpression != null || collectionVariable != null || collectionString != null;
    }

    protected boolean isExtraScopeNeeded(FlowNode flowNode) {
        return flowNode.getSubProcess() != null;
    }

    protected int resolveLoopCardinality(DelegateExecution execution) {
        // Using Number since expr can evaluate to eg. Long (which is also the default for Juel)
        Object value = loopCardinalityExpression.getValue(execution);
        if (value instanceof Number) {
            return ((Number) value).intValue();

        } else if (value instanceof String) {
            return Integer.valueOf((String) value);

        } else {
            throw new FlowableIllegalArgumentException("Could not resolve loopCardinality expression '" + loopCardinalityExpression.getExpressionText() + "': not a number nor number String");
        }
    }

    protected void setLoopVariable(DelegateExecution execution, String variableName, Object value) {
        execution.setVariableLocal(variableName, value);
    }

    protected Integer getLocalLoopVariable(DelegateExecution execution, String variableName) {
        Map<String, Object> localVariables = execution.getVariablesLocal();
        if (localVariables.containsKey(variableName)) {
            return (Integer) execution.getVariableLocal(variableName);
            
        } else if (!execution.isMultiInstanceRoot()) {
            DelegateExecution parentExecution = execution.getParent();
            localVariables = parentExecution.getVariablesLocal();
            if (localVariables.containsKey(variableName)) {
                return (Integer) parentExecution.getVariableLocal(variableName);
                

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Make the expression evaluate to a Number or an integer String, e.g. loopCardinality=3 or ${nrOfItems} with nrOfItems being an Integer.
  2. Initialize the referenced variable with an Integer value before the activity executes.
  3. Strip formatting from numeric strings ('3 ' or '3.0' will not parse) and store plain integers.
  4. Change a boolean/wrong-typed variable to the intended count variable.
  5. Validate the cardinality expression in a unit test before deploying.

Example fix

// before
vars.put("nrOfApprovers", "three");
// after
vars.put("nrOfApprovers", 3);
Defensive patterns

Strategy: validation

Validate before calling

Object c = execution.getVariable("nrOfApprovers");
boolean ok = (c instanceof Number) || (c instanceof String && c.toString().trim().matches("\\d+"));
if (!ok) throw new IllegalStateException("loopCardinality value must be a number or numeric string, got: " + c);

Type guard

boolean isCardinalityValue(Object v) {
    return v instanceof Number || (v instanceof String && ((String) v).trim().matches("\\d+"));
}

Try / catch

try {
    return task.execute(execution);
} catch (FlowableIllegalArgumentException ex) {
    if (ex.getMessage().contains("loopCardinality")) {
        logger.error("Invalid loopCardinality expression result: {}", ex.getMessage());
    }
    throw ex;
}

Prevention

When it happens

Trigger: <multiInstanceLoopCharacteristics><loopCardinality>${expr}</loopCardinality> where expr evaluates to null, a Boolean, a non-numeric String like 'three', or an object; also Integer.valueOf failing on strings with spaces or decimals.

Common situations: loopCardinality pointing at an unset (null) variable; variable holding '3.5' or '3 ' (non-parseable string); expression returning a Long/BigInteger path is fine but a custom object or boolean is returned; copy-paste of an expression referencing the wrong variable.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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