flowable/flowable-engine · error · ActivitiIllegalArgumentException
Expression did not resolve to a string or collection of…
Error message
Expression did not resolve to a string or collection of strings
What it means
Thrown in handleAssignments when a candidateGroups (activiti:candidateGroups) expression resolves to a non-null value that is neither a String nor a Collection. The engine accepts a delimited string of group names or a Collection of them and rejects any other type as ActivitiIllegalArgumentException.
Solutions
- Ensure the expression resolves to a String of group names (comma/semicolon separated) e.g. ${groupsString}
- Ensure the expression resolves to a java.util.Collection of Strings; convert arrays with Arrays.asList(...) in the bean
- Fix the variable type set upstream so it matches String or Collection<String>
- Add a conversion in the referenced bean getter to return List<String>
Example fix
// before (bean returns String[])
public String[] getCandidateGroups() { ... }
// after
public List<String> getCandidateGroups() { return Arrays.asList(...); } Defensive patterns
Strategy: validation
Validate before calling
Object v = execution.getVariable("groupNames");
if (v != null && !(v instanceof String) && !(v instanceof Collection)) {
throw new IllegalArgumentException("groupNames must be String or Collection<String>");
} Type guard
boolean ok(Object v) { return v == null || v instanceof String || v instanceof Collection; } Try / catch
try {
taskService.complete(taskId);
} catch (ActivitiIllegalArgumentException e) {
if (e.getMessage().contains("did not resolve to a string or collection")) { /* fix variable type */ }
throw e;
} Prevention
- Use List<String> for candidate group variables, never arrays or Maps
- Delimit multiple groups in a single String with commas if not using a Collection
- Test assignment expressions during process model validation
When it happens
Trigger: Executing a user task whose candidateGroups expression (e.g. ${groupNames}) evaluates to an Integer, Boolean, Map, or other non-String/non-Collection object.
Common situations: Referencing a numeric variable in candidateGroups; a bean method returning Set wrapped differently or an array (arrays are not Collections); wrong variable assigned in a previous service task.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Category expression does not resolve to a string:
- Category expression does not resolve to a string
- ' didn't resolve to a Collection
- completionCondition ' ' does not evaluate to a boolean value
- Custom properties resolver expression " + expression + "…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/8a34b5aa1f6554ad.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/UserTaskActivityBehavior.java:269
if (ownerExpression != null) {
Object ownerExpressionValue = ownerExpression.getValue(execution);
String ownerValue = null;
if (ownerExpressionValue != null) {
ownerValue = ownerExpressionValue.toString();
}
task.setOwner(ownerValue);
}
if (candidateGroupExpressions != null && !candidateGroupExpressions.isEmpty()) {
for (Expression groupIdExpr : candidateGroupExpressions) {
Object value = groupIdExpr.getValue(execution);
if (value instanceof String) {
List<String> candidates = extractCandidates((String) value);
task.addCandidateGroups(candidates);
} else if (value instanceof Collection) {
task.addCandidateGroups((Collection) value);
} else {
throw new ActivitiIllegalArgumentException("Expression did not resolve to a string or collection of strings");
}
}
}
if (candidateUserExpressions != null && !candidateUserExpressions.isEmpty()) {
for (Expression userIdExpr : candidateUserExpressions) {
Object value = userIdExpr.getValue(execution);
if (value instanceof String) {
List<String> candiates = extractCandidates((String) value);
task.addCandidateUsers(candiates);
} else if (value instanceof Collection) {
task.addCandidateUsers((Collection) value);
} else {
throw new ActivitiException("Expression did not resolve to a string or collection of strings");
}
}
}
View on GitHub (pinned to d6d39ce1c6)