Activiti/Activiti · 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 resolveNrOfInstances yields a negative count for a sequential multi-instance activity. Zero is explicitly allowed (returns immediately with no instances), but any negative value is rejected as an illegal argument.

Solutions

  1. Validate/clamp the count before the activity: Math.max(0, value) when setting the variable
  2. Fix the expression to be non-negative or guard the preceding service task that computes it
  3. If an empty loop should be valid, ensure the value is 0 (allowed) rather than a negative number

Example fix

// before
<completionCondition/> <!-- n/a --> <mi:loopCardinality>${count}</mi:loopCardinality> <!-- count = -2 -->

// after
// in a delegate before the MI activity
execution.setVariable("count", Math.max(0, requestedCount));
Defensive patterns

Strategy: validation

Validate before calling

Integer n = (Integer) execution.getVariable("n");
if (n == null || n < 0) throw new IllegalStateException("sequential MI instance count 'n' must be >= 0 (0 is allowed), got: " + n);

Type guard

boolean isValidSequentialInstanceCount(Integer n) {
    return n != null && n >= 0;
}

Prevention

When it happens

Trigger: loopCardinality expression or numberOfInstances variable resolves negative — e.g. '${list.size() - skip}' with skip > size, or a variable initialized to -1; subclass of the parallel variant, so 0 is tolerated here but must still never be negative.

Common situations: Arithmetic on collections that may be empty or smaller than expected; countdown-style variables that start below zero; validation gap where the caller assumed Activiti clamps the value (it does not).

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 Activiti/Activiti@56435b1a97 (2026-09-09). Data as JSON: /api/errors/549f215611569aeb. Report an issue: GitHub.

Appendix: source

Thrown at activiti-core/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/SequentialMultiInstanceBehavior.java:45

import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;

public class SequentialMultiInstanceBehavior extends MultiInstanceActivityBehavior {

    private static final long serialVersionUID = 1L;

    public SequentialMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior 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.
     */
    protected int createInstances(DelegateExecution multiInstanceExecution) {
        int nrOfInstances = resolveNrOfInstances(multiInstanceExecution);
        if (nrOfInstances == 0) {
            return nrOfInstances;
        } else if (nrOfInstances < 0) {
            throw new ActivitiIllegalArgumentException(
                "Invalid number of instances: must be a non-negative integer value" + ", but was " + nrOfInstances
            );
        }

        // Create child execution that will execute the inner behavior
        ExecutionEntity childExecution = Context.getCommandContext()
            .getExecutionEntityManager()
            .createChildExecution((ExecutionEntity) multiInstanceExecution);
        childExecution.setCurrentFlowElement(multiInstanceExecution.getCurrentFlowElement());
        multiInstanceExecution.setMultiInstanceRoot(true);
        multiInstanceExecution.setActive(false);

        // Set Multi-instance variables
        setLoopVariable(multiInstanceExecution, NUMBER_OF_INSTANCES, nrOfInstances);
        setLoopVariable(multiInstanceExecution, NUMBER_OF_COMPLETED_INSTANCES, 0);
        setLoopVariable(multiInstanceExecution, NUMBER_OF_ACTIVE_INSTANCES, 1);
        setLoopVariable(childExecution, getCollectionElementIndexVariable(), 0);
        logLoopDetails(multiInstanceExecution, "initialized", 0, 0, 1, nrOfInstances);

View on GitHub (pinned to 56435b1a97)