{"record":{"id":"0930597bc377907d","repo":"flowable/flowable-engine","slug":"invalid-number-of-instances-must-be-a-non-negativ-093059","errorCode":null,"errorMessage":"Invalid number of instances: must be a non-negative integer value, but was ${nrOfInstances}","messagePattern":"Invalid number of instances: must be a 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/SequentialMultiInstanceBehavior.java","lineNumber":40,"sourceCode":"\n/**\n * @author Joram Barrez\n * @author Falko Menge\n */\npublic class SequentialMultiInstanceBehavior extends MultiInstanceActivityBehavior {\n\n    public SequentialMultiInstanceBehavior(ActivityImpl activity, ActivityBehavior innerActivityBehavior) {\n        super(activity, innerActivityBehavior);\n    }\n\n    /**\n     * Handles the sequential case of spawning the instances. Will only create one instance, since at most one instance can be active.\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 a 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, getCollectionElementIndexVariable(), 0);\n        setLoopVariable(execution, NUMBER_OF_ACTIVE_INSTANCES, 1);\n        logLoopDetails(execution, \"initialized\", 0, 0, 1, nrOfInstances);\n\n        if (nrOfInstances > 0) {\n            executeOriginalBehavior(execution, 0);\n        }\n    }\n\n    /**\n     * Called when the wrapped {@link ActivityBehavior} calls the {@link AbstractBpmnActivityBehavior#leave(ActivityExecution)} method. Handles the completion of one instance, and executes the logic\n     * for the sequential behavior.\n     */","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/SequentialMultiInstanceBehavior.java#L22-L58","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (BPMN)\n<multiInstanceLoopCharacteristics isSequential=\"true\">\n  <loopCardinality>${nrOfApprovers - 1}</loopCardinality>\n</multiInstanceLoopCharacteristics>\n// after\n<multiInstanceLoopCharacteristics isSequential=\"true\">\n  <loopCardinality>${approvedCount}</loopCardinality>\n</multiInstanceLoopCharacteristics>\n<!-- plus a guard: if (approvedCount < 0) approvedCount = 0; -->","handlingStrategy":"validation","validationCode":"Object v = execution.getVariable(\"approvedCount\");\nint nr = v instanceof Number ? ((Number) v).intValue() : -1;\nif (nr < 0) {\n    throw new IllegalArgumentException(\"approvedCount must be >= 0, was \" + nr);\n}","typeGuard":"public static boolean isNonNegativeInt(Object v) {\n    return v instanceof Number && ((Number) v).intValue() >= 0;\n}","tryCatchPattern":"try {\n    runtimeService.startProcessInstanceByKey(key, vars);\n} catch (org.activiti.engine.ActivitiIllegalArgumentException e) {\n    if (e.getMessage().contains(\"Invalid number of instances\")) {\n        // fix cardinality/variable and retry with sanitized value\n    } else { throw e; }\n}","preventionTips":["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"],"tags":["bpmn","multi-instance","validation","expression"],"backgroundTag":"invalid-argument-value","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}