flowable/flowable-engine · error · FlowableIllegalArgumentException

Could not evaluate collection for repetition rule on plan it

Error message

Could not evaluate collection for repetition rule on plan item with id '${planItemInstanceEntity.getId()}', collection variable name '${repetitionRule.getCollectionVariableName()}' evaluated to '${collection}', but needs to be a collection, an iterable or an ArrayNode (JSON).

What it means

ExpressionUtil.evaluateRepetitionCollectionVariableValue resolves the repetition rule's collection variable and accepts only Collection, Iterable, or JSON ArrayNode values. Any other type (String, Map handled elsewhere?, scalar, null beyond the earlier guard) causes this FlowableIllegalArgumentException, since multi-instance/repetition requires something iterable to create plan item instances from.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/util/ExpressionUtil.java:168

            return null;
        }

        String collectionExpression = repetitionRule.getCollectionVariableName();

        if (!(collectionExpression.startsWith("${") || collectionExpression.startsWith("#{"))) {
            collectionExpression = "${vars:getOrDefault('" + collectionExpression + "', null)}";
        }

        Object collection = evaluateExpression(commandContext, planItemInstanceEntity, collectionExpression);
        if (collection == null) {
            return null;
        }

        if (collection instanceof Iterable) {
            return (Iterable<Object>) collection;
        }

        throw new FlowableIllegalArgumentException("Could not evaluate collection for repetition rule on plan item with id '" + planItemInstanceEntity.getId() +
            "', collection variable name '" + repetitionRule.getCollectionVariableName() + "' evaluated to '" + collection +
            "', but needs to be a collection, an iterable or an ArrayNode (JSON).");
    }

    /**
     * Returns true, if: the given plan item instance has a repetition rule at all and if so, if it has a condition witch is satisfied and all in combination
     * with the optional max instance count attribute. If the repetition rule evaluates to true, this normally means that there should be an additional
     * instance of the plan item created.
     *
     * @param commandContext the command context in which this evaluation is taking place
     * @param planItemInstanceEntity the plan item instance entity to test for a repetition rule to evaluate to true
     * @param planItemInstanceContainer the container (usually the parent stage of the plan item instance) to get access to child plan items
     * @return true, if there is a repetition rule of the plan item instance currently evaluating to true with all of its conditions and attributes
     */
    public static boolean evaluateRepetitionRule(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity,
            PlanItemInstanceContainer planItemInstanceContainer) {
        
        RepetitionRule repetitionRule = getRepetitionRule(planItemInstanceEntity);

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Set the collection variable to a java.util.Collection/List, an Iterable, or a com.fasterxml.jackson.databind.node.ArrayNode
  2. If the source data is a delimited String, split it first: Arrays.asList(csv.split(",")) and store that as the variable
  3. Ensure the JSON payload is parsed as an ArrayNode (e.g. objectMapper.readTree returning an array) not a scalar/object
  4. Add a check/log of the variable's type at runtime to catch upstream overwrites

Example fix

// before
execution.setVariable("items", "item1,item2");
// after
execution.setVariable("items", Arrays.asList("item1", "item2"));
Defensive patterns

Strategy: validation

Validate before calling

Object collection = variableContainer.getVariable(repetitionRule.getCollectionVariableName());
if (!(collection instanceof Collection) && !(collection instanceof Iterable) && !(collection instanceof ArrayNode)) {
    throw new IllegalStateException("Repetition collection variable '" + repetitionRule.getCollectionVariableName() + "' must be Collection/Iterable/ArrayNode, got: " + (collection == null ? "null" : collection.getClass()));
}

Type guard

boolean isRepetitionCollection(Object v) { return v instanceof Iterable || v instanceof ArrayNode; }

Try / catch

try { evaluateRepetition(); } catch (FlowableIllegalArgumentException e) { if (e.getMessage().contains("repetition rule")) { log.error("Collection variable '{}' has wrong type", repetitionRule.getCollectionVariableName()); throw e; } throw e; }

Prevention

When it happens

Trigger: A plan item has a repetition rule with a collectionVariableName whose variable resolves to a non-iterable value — e.g. a comma-separated String like 'a,b,c', a single object, or a number — when the engine evaluates the repetition rule at plan item creation.

Common situations: Storing CSV strings in a variable and pointing collectionVariableName at them; a variable overwritten by later logic from a List to a scalar; JSON returned as an ObjectNode rather than ArrayNode; type changes after a model refactor.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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