flowable/flowable-engine · error · FlowableIllegalArgumentException
Candidate group list is empty
Error message
Candidate group list is empty
What it means
TaskQueryImpl.taskCandidateGroupIn() throws this when the collection is non-null but empty. An empty IN list is meaningless or invalid SQL, so Flowable rejects it explicitly. Treat 'no filter' as not calling the setter, not as an empty list.
Solutions
- Call taskCandidateGroupIn() only when the collection has at least one element.
- On empty, either skip the filter or short-circuit to an empty result set if that matches your authorization model.
- Fix group resolution so expected groups are actually populated.
- Do not use empty collections to mean 'match nothing'; handle that case in caller logic.
Example fix
// before
TaskQuery query = taskService.createTaskQuery().taskCandidateGroupIn(groups);
// after
if (groups == null || groups.isEmpty()) {
return Collections.emptyList();
}
TaskQuery query = taskService.createTaskQuery().taskCandidateGroupIn(groups); Defensive patterns
Strategy: validation
Validate before calling
if (candidateGroups == null || candidateGroups.isEmpty()) {
throw new IllegalArgumentException("candidateGroups must contain at least one group");
}
query.taskCandidateGroupIn(candidateGroups); Type guard
boolean isNonEmptyCandidateGroups(Collection<String> g) { return g != null && !g.isEmpty(); } Try / catch
try {
query.taskCandidateGroupIn(groups);
} catch (FlowableIllegalArgumentException e) {
logger.warn("Empty candidate group list: {}", e.getMessage());
return Collections.emptyList(); // no groups -> no candidate tasks
} Prevention
- Handle the no-groups authorization case explicitly before querying
- Never pass empty collections to IN-style filters
- Validate collections after filtering (e.g. by tenant or authorization)
- Add tests for empty group-list scenarios
When it happens
Trigger: Calling taskQuery.taskCandidateGroupIn(new ArrayList<>()) or a list reduced to zero elements by prior filtering/authorization logic.
Common situations: User belongs to no groups so the resolved group list is empty; authorization filter stripped all groups; default empty list passed unconditionally in generic query-builder code.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Candidate group is null
- Candidate group list is empty
- Candidate group list is null
- Invalid query usage: cannot set both candidateGroup and…
- Invalid query usage: cannot set both candidateGroupIn and…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/0512d90e7b5b1ea5.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/TaskQueryImpl.java:664
if (orActive) {
currentOrQueryObject.bothCandidateAndAssigned = true;
currentOrQueryObject.userIdForCandidateAndAssignee = userIdForCandidateAndAssignee;
} else {
this.bothCandidateAndAssigned = true;
this.userIdForCandidateAndAssignee = userIdForCandidateAndAssignee;
}
return this;
}
@Override
public TaskQuery taskCandidateGroupIn(Collection<String> candidateGroups) {
if (candidateGroups == null) {
throw new FlowableIllegalArgumentException("Candidate group list is null");
}
if (candidateGroups.isEmpty()) {
throw new FlowableIllegalArgumentException("Candidate group list is empty");
}
if (candidateGroup != null) {
throw new FlowableIllegalArgumentException("Invalid query usage: cannot set both candidateGroupIn and candidateGroup");
}
if (orActive) {
currentOrQueryObject.candidateGroups = candidateGroups;
} else {
this.candidateGroups = candidateGroups;
}
return this;
}
@Override
public TaskQuery ignoreAssigneeValue() {
if (orActive) {
currentOrQueryObject.ignoreAssigneeValue = true;View on GitHub (pinned to d6d39ce1c6)