flowable/flowable-engine · error · ActivitiIllegalArgumentException
Invalid number of instances: must be a non-negative integer
Error message
Invalid number of instances: must be a non-negative integer value, but was ${nrOfInstances} What it means
Thrown by SequentialMultiInstanceBehavior.createInstances when the resolved number of instances for a sequential multi-instance activity is negative. The engine requires nrOfInstances to be a non-negative integer before it can initialize loop variables (loopCounter, nrOfCompletedInstances). This almost always means the loopCardinality expression or collection-based cardinality resolved to a bad value.
Source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/SequentialMultiInstanceBehavior.java:40
/**
* @author Joram Barrez
* @author Falko Menge
*/
public class SequentialMultiInstanceBehavior extends MultiInstanceActivityBehavior {
public SequentialMultiInstanceBehavior(ActivityImpl activity, ActivityBehavior innerActivityBehavior) {
super(activity, innerActivityBehavior);
}
/**
* Handles the sequential case of spawning the instances. Will only create one instance, since at most one instance can be active.
*/
@Override
protected void createInstances(ActivityExecution execution) {
int nrOfInstances = resolveNrOfInstances(execution);
if (nrOfInstances < 0) {
throw new ActivitiIllegalArgumentException("Invalid number of instances: must be a non-negative integer value"
+ ", but was " + nrOfInstances);
}
setLoopVariable(execution, NUMBER_OF_INSTANCES, nrOfInstances);
setLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES, 0);
setLoopVariable(execution, getCollectionElementIndexVariable(), 0);
setLoopVariable(execution, NUMBER_OF_ACTIVE_INSTANCES, 1);
logLoopDetails(execution, "initialized", 0, 0, 1, nrOfInstances);
if (nrOfInstances > 0) {
executeOriginalBehavior(execution, 0);
}
}
/**
* Called when the wrapped {@link ActivityBehavior} calls the {@link AbstractBpmnActivityBehavior#leave(ActivityExecution)} method. Handles the completion of one instance, and executes the logic
* for the sequential behavior.
*/View on GitHub (pinned to d6d39ce1c6)
Solutions
- Set a valid loopCardinality (non-negative int) or a collection on the multiInstanceLoopCharacteristics of the activity
- Check the expression/variable used for cardinality at runtime and ensure the process variable exists and is >= 0
- Log or assert the resolved value before the multi-instance activity (e.g. a listener or script task) to find where the negative value originates
- If using a collection, verify the collection expression resolves to a real Collection bean/variable, not null
Example fix
// before (BPMN)
<multiInstanceLoopCharacteristics isSequential="true">
<loopCardinality>${nrOfApprovers - 1}</loopCardinality>
</multiInstanceLoopCharacteristics>
// after
<multiInstanceLoopCharacteristics isSequential="true">
<loopCardinality>${approvedCount}</loopCardinality>
</multiInstanceLoopCharacteristics>
<!-- plus a guard: if (approvedCount < 0) approvedCount = 0; --> Defensive patterns
Strategy: validation
Validate before calling
Object v = execution.getVariable("approvedCount");
int nr = v instanceof Number ? ((Number) v).intValue() : -1;
if (nr < 0) {
throw new IllegalArgumentException("approvedCount must be >= 0, was " + nr);
} Type guard
public static boolean isNonNegativeInt(Object v) {
return v instanceof Number && ((Number) v).intValue() >= 0;
} Try / catch
try {
runtimeService.startProcessInstanceByKey(key, vars);
} catch (org.activiti.engine.ActivitiIllegalArgumentException e) {
if (e.getMessage().contains("Invalid number of instances")) {
// fix cardinality/variable and retry with sanitized value
} else { throw e; }
} Prevention
- Always configure loopCardinality or a collection on multiInstanceLoopCharacteristics
- Clamp computed cardinality values to >= 0 before starting the process
- Write a unit test deploying the BPMN and starting with boundary cardinality values (0, negative)
- Validate process variables used in cardinality expressions at process start
When it happens
Trigger: A multi-instance activity with loopCardinality evaluated to a negative number (e.g. an expression like ${count - 5} yielding -2), or resolveNrOfInstances returning -1 because neither loopCardinality nor a collection was configured on the multi-instance activity.
Common situations: Missing loopCardinality/collectionDefinition on multiInstanceLoopCharacteristics in the BPMN XML; a process variable used in the cardinality expression is unset or negative; a collection-resolved count computed as negative during script/delegate logic; copying a process definition from another engine with different loop-variable semantics.
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
- completionCondition '${activeCompletionCondition}' does not
- Couldn't resolve collection expression${collectionExpression
- Could not resolve loopCardinality expression '${loopCardinal
- Invalid number of instances: must be a non-negative integer
- ${collectionExpressionText}' didn't resolve to a Collection
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/0930597bc377907d.
Report an issue: GitHub.