flowable/flowable-engine · error · FlowableIllegalArgumentException
Invalid query usage: cannot set both candidateGroupIn and…
Error message
Invalid query usage: cannot set both candidateGroupIn and candidateGroup
What it means
TaskQueryImpl.taskCandidateGroupIn() throws this when taskCandidateGroup() has already been called (candidateGroup != null). The single-group and group-list filters are mutually exclusive; setting both makes the query ambiguous. Flowable fails fast with FlowableIllegalArgumentException instead of emitting conflicting SQL.
Solutions
- Pick one filter: taskCandidateGroup() for a single group or taskCandidateGroupIn() for a list.
- Use taskCandidateGroupIn(Collections.singletonList(group)) when the input may be single or multiple.
- Instantiate a new TaskQuery per use instead of reusing cached instances.
- Refactor the query-composition code so the two filter branches are exclusive.
Example fix
// before
query.taskCandidateGroup("management");
query.taskCandidateGroupIn(groups);
// after
if (groups != null && !groups.isEmpty()) {
query.taskCandidateGroupIn(groups);
} else {
query.taskCandidateGroup("management");
} Defensive patterns
Strategy: validation
Validate before calling
if (useSingleGroup) {
query.taskCandidateGroup(group);
} else if (groups != null && !groups.isEmpty()) {
query.taskCandidateGroupIn(groups);
} Try / catch
try {
query.taskCandidateGroupIn(groups);
} catch (FlowableIllegalArgumentException e) {
logger.warn("candidateGroup already set: {}", e.getMessage());
query = taskService.createTaskQuery();
} Prevention
- Apply only one of taskCandidateGroup / taskCandidateGroupIn per query
- Use singletonList for single-group inputs to standardize on the list API
- Avoid reusing TaskQuery instances that may carry prior filters
- Enforce exclusivity inside shared query-builder helpers
When it happens
Trigger: Calling taskCandidateGroupIn(list) after taskCandidateGroup("g") on the same query, including reused query instances or query builders that apply both filters.
Common situations: Merging two query-building features (single group vs multi-group); a TaskQuery field reused across requests keeping prior state; dynamic builders that always call both setters.
Related errors
- Invalid query usage: cannot set both candidateGroup and…
- Invalid query usage: cannot set candidateGroup
- Candidate group is null
- Candidate group list is empty
- Candidate group list is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/b84e4e5dc62a6409.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/TaskQueryImpl.java:668
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;
} else {
this.ignoreAssigneeValue = true;
}
return this;View on GitHub (pinned to d6d39ce1c6)