flowable/flowable-engine · error · FlowableIllegalArgumentException

Variable '${obj}' was not found

Error message

Variable '${obj}' was not found

What it means

Thrown by MultiInstanceActivityBehavior.resolveAndValidateCollection when the configured collection attribute names a process variable that does not exist in the execution: execution.getVariable(obj) returns null, so the behavior cannot build the list of multi-instance elements. The '${obj}' in the message is the variable name taken from the collection configuration.

Source

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

    protected Collection resolveAndValidateCollection(DelegateExecution execution) {
        Object obj = resolveCollection(execution);
        if (collectionHandler != null ) {           
            return createFlowableCollectionHandler(collectionHandler, execution).resolveCollection(obj, execution);
        } else {
            if (obj instanceof Collection) {
                return (Collection) obj;
                
            } else if (obj instanceof Iterable) {
                return iterableToCollection((Iterable) obj);
                
            } else if (obj instanceof String) {
                Object collectionVariable = execution.getVariable((String) obj);
                if (collectionVariable instanceof Collection) {
                    return (Collection) collectionVariable;
                } else if (collectionVariable instanceof Iterable) {
                    return iterableToCollection((Iterable) collectionVariable);
                } else if (collectionVariable == null) {
                    throw new FlowableIllegalArgumentException("Variable '" + obj + "' was not found");
                } else {
                    throw new FlowableIllegalArgumentException("Variable '" + obj + "':" + collectionVariable + " is not a Collection");
                }
                
            } else {
                throw new FlowableIllegalArgumentException(buildUnresolvedCollectionExceptionMessage());
            }
        }
    }

    protected String buildUnresolvedCollectionExceptionMessage() {
        StringBuilder exceptionStringBuilder = new StringBuilder("Couldn't resolve collection expression");
        if (collectionExpression != null) {
            exceptionStringBuilder.append(" (");
            exceptionStringBuilder.append(collectionExpression.getExpressionText());
            exceptionStringBuilder.append(")");
        }
        exceptionStringBuilder.append(", variable reference");

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Set the collection variable before the multi-instance activity runs, e.g. pass it in the process start variables map.
  2. Correct the variable name in the flowable:collection attribute to match the actual variable.
  3. Initialize the variable in a start listener or a preceding service task if it is derived at runtime.
  4. Add a guard service task that checks the variable exists and fails early with a clearer message.
  5. Use a collection expression resolving to a default empty list if zero instances is acceptable.

Example fix

// before
runtimeService.startProcessInstanceByKey("orderProcess");
// after: provide the collection variable expected by flowable:collection="assigneeList"
Map<String, Object> vars = new HashMap<>();
vars.put("assigneeList", List.of("kermit", "gonzo"));
runtimeService.startProcessInstanceByKey("orderProcess", vars);
Defensive patterns

Strategy: validation

Validate before calling

Map<String, Object> vars = new HashMap<>();
vars.put("assigneeList", java.util.Arrays.asList("kermit", "gonzo")); // must be present & non-null before the activity
runtimeService.startProcessInstanceByKey("orderProcess", vars);

Type guard

boolean validCollection(Object v) { return v instanceof Collection || v instanceof Iterable; }

Try / catch

try {
    runtimeService.trigger(executionId);
} catch (FlowableIllegalArgumentException ex) {
    if (ex.getMessage().contains("was not found")) {
        logger.error("Missing collection variable: {}", ex.getMessage());
    }
    throw ex;
}

Prevention

When it happens

Trigger: flowable:collection="assigneeList" on a multi-instance activity where process variable 'assigneeList' was never set (or was removed / set with a different name / not visible on this scope) before the multi-instance behavior executes.

Common situations: Caller forgot to pass the collection variable when starting the process (runtimeService.startProcessInstanceByKey(vars)); variable set under a different name or with a typo; variable set only on a child scope that has ended; race where the variable is set asynchronously after the task is reached.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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