{"record":{"id":"c2894fdcb747c178","repo":"flowable/flowable-engine","slug":"invalid-number-of-instances-must-be-non-negative-c2894f","errorCode":null,"errorMessage":"Invalid number of instances: must be non-negative integer value, but was ${nrOfInstances}","messagePattern":"Invalid number of instances: must be non-negative integer value, but was (.+?)","errorType":"validation","errorClass":"ActivitiIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/ParallelMultiInstanceBehavior.java","lineNumber":40,"sourceCode":"import org.flowable.engine.impl.delegate.ActivityBehavior;\n\n/**\n * @author Joram Barrez\n */\npublic class ParallelMultiInstanceBehavior extends MultiInstanceActivityBehavior {\n\n    public ParallelMultiInstanceBehavior(ActivityImpl activity, ActivityBehavior originalActivityBehavior) {\n        super(activity, originalActivityBehavior);\n    }\n\n    /**\n     * Handles the parallel case of spawning the instances. Will create child executions accordingly for every instance needed.\n     */\n    @Override\n    protected void createInstances(ActivityExecution execution) {\n        int nrOfInstances = resolveNrOfInstances(execution);\n        if (nrOfInstances < 0) {\n            throw new ActivitiIllegalArgumentException(\"Invalid number of instances: must be non-negative integer value\"\n                    + \", but was \" + nrOfInstances);\n        }\n\n        setLoopVariable(execution, NUMBER_OF_INSTANCES, nrOfInstances);\n        setLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES, 0);\n        setLoopVariable(execution, NUMBER_OF_ACTIVE_INSTANCES, nrOfInstances);\n\n        List<ActivityExecution> concurrentExecutions = new ArrayList<>();\n        for (int loopCounter = 0; loopCounter < nrOfInstances; loopCounter++) {\n            ActivityExecution concurrentExecution = execution.createExecution();\n            concurrentExecution.setActive(true);\n            concurrentExecution.setConcurrent(true);\n            concurrentExecution.setScope(false);\n\n            // In case of an embedded subprocess, and extra child execution is required\n            // Otherwise, all child executions would end up under the same parent,\n            // without any differentiation to which embedded subprocess they belong\n            if (isExtraScopeNeeded()) {","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/ParallelMultiInstanceBehavior.java#L22-L58","documentation":"Thrown by ParallelMultiInstanceBehavior.createInstances after resolving the instance count: if nrOfInstances is negative, the engine cannot spawn a negative number of child executions, so it throws ActivitiIllegalArgumentException. Note the check is < 0; zero is accepted and the activity completes immediately.","triggerScenarios":"resolveNrOfInstances derives a negative count: loopCardinality expression evaluates to a negative number, or a collection variable whose Collection implementation reports a negative size (custom/broken Collection), via MultiInstanceActivityBehavior.resolveNrOfInstances.","commonSituations":"A variable like remaining = total - completed going below zero and being fed directly into loopCardinality; custom Collection implementations with buggy size(); arithmetic in the UEL expression itself (e.g. ${a - b}) yielding a negative result.","solutions":["Clamp the variable before the activity: execution.setVariable(\"nrOfItems\", Math.max(0, computed))","Fix the source expression so it cannot go negative, e.g. ${a > b ? a - b : 0}","If a custom Collection is used, verify its size() implementation returns a correct non-negative value"],"exampleFix":"// before\nexecution.setVariable(\"nrOfItems\", total - completed); // can be negative\n// after\nexecution.setVariable(\"nrOfItems\", Math.max(0, total - completed));","handlingStrategy":"validation","validationCode":"int nr = ((Number) execution.getVariable(\"nrOfItems\")).intValue();\nif (nr < 0) {\n    execution.setVariable(\"nrOfItems\", 0); // or reject the transition\n}","typeGuard":"public static boolean isNonNegativeInt(Object v) {\n    return v instanceof Number && ((Number) v).intValue() >= 0;\n}","tryCatchPattern":"try {\n    runtimeService.signal(executionId);\n} catch (org.activiti.engine.ActivitiIllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Invalid number of instances\")) {\n        // clamp the cardinality variable and retry the activity\n    }\n}","preventionTips":["Clamp computed counts with Math.max(0, x) before assigning loopCardinality variables","Avoid raw subtraction expressions inside loopCardinality expressions","Sanitize collection sizes from external data sources before feeding multi-instance loops","Add a start listener that validates the cardinality variable range"],"tags":["bpmn","multi-instance","negative-value","validation"],"backgroundTag":"value-out-of-range","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}