flowable/flowable-engine · error · FlowableIllegalArgumentException
Invalid query usage: cannot set both candidateGroup and…
Error message
Invalid query usage: cannot set both candidateGroup and candidateGroupIn
What it means
TaskQueryImpl.taskCandidateGroup() throws this when taskCandidateGroupIn() has already been called (candidateGroups != null). The two setters represent mutually exclusive filtering strategies (single group vs list), and combining them would produce an ambiguous query. Flowable rejects the conflicting call at build time.
Solutions
- Use either taskCandidateGroup() or taskCandidateGroupIn(), never both on the same query.
- Build a fresh query object instead of reusing a cached TaskQuery instance.
- Wrap the single group in a list and call taskCandidateGroupIn(Collections.singletonList(group)) when the source may vary.
- Refactor query composition logic so only one candidate filter branch executes.
Example fix
// before
query.taskCandidateGroupIn(groups);
query.taskCandidateGroup("management");
// 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.taskCandidateGroup(group);
} catch (FlowableIllegalArgumentException e) {
logger.warn("Conflicting candidate filters: {}", e.getMessage());
query = taskService.createTaskQuery(); // rebuild with only one filter
} Prevention
- Never combine taskCandidateGroup and taskCandidateGroupIn on one query
- Create a new TaskQuery instead of reusing instances
- Centralize candidate filtering in one helper that enforces exclusivity
- Wrap single groups in singletonList and use only taskCandidateGroupIn when the source varies
When it happens
Trigger: Calling taskCandidateGroup("g1") after taskCandidateGroupIn(list), or building one query object incrementally/reused where both setters got invoked (including inside or() branches that share state checks).
Common situations: Query builder reused across requests retaining earlier state; code merged from two features each setting a different candidate filter; dynamic query composition adding both filters unconditionally.
Related errors
- Invalid query usage: cannot set both candidateGroupIn 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/85548ecf0718ab75.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/TaskQueryImpl.java:626
if (involvedGroups.isEmpty()) {
throw new FlowableIllegalArgumentException("Involved groups are empty");
}
if (orActive) {
currentOrQueryObject.involvedGroups = involvedGroups;
} else {
this.involvedGroups = involvedGroups;
}
return this;
}
@Override
public TaskQueryImpl taskCandidateGroup(String candidateGroup) {
if (candidateGroup == null) {
throw new FlowableIllegalArgumentException("Candidate group is null");
}
if (candidateGroups != null) {
throw new FlowableIllegalArgumentException("Invalid query usage: cannot set both candidateGroup and candidateGroupIn");
}
if (orActive) {
currentOrQueryObject.candidateGroup = candidateGroup;
} else {
this.candidateGroup = candidateGroup;
}
return this;
}
@Override
public TaskQuery taskCandidateOrAssigned(String userIdForCandidateAndAssignee) {
if (candidateGroup != null) {
throw new FlowableIllegalArgumentException("Invalid query usage: cannot set candidateGroup");
}
if (candidateUser != null) {
throw new FlowableIllegalArgumentException("Invalid query usage: cannot set both candidateGroup and candidateUser");
}View on GitHub (pinned to d6d39ce1c6)