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
taskCandidateGroupIn(Collection<String>) throws this error when the query already has candidateGroup (from taskCandidateGroup) set. candidateGroup and candidateGroupIn are mutually exclusive filters; only one representation can be applied to the generated SQL.
Solutions
- Remove either the taskCandidateGroup(...) or the taskCandidateGroupIn(...) call on the same query object.
- Use taskCandidateGroupIn(Collections.singletonList(group)) for everything so only one API is ever used.
- Build a new query instance when the filter strategy changes.
Example fix
// before
query.taskCandidateGroup("backoffice");
query.taskCandidateGroupIn(groupList); // throws
// after
List<String> effective = new ArrayList<>(groupList);
effective.add("backoffice");
query.taskCandidateGroupIn(effective); Defensive patterns
Strategy: validation
Validate before calling
// merge both sources into one list and use only taskCandidateGroupIn
List<String> allGroups = new ArrayList<>();
if (candidateGroup != null) { allGroups.add(candidateGroup); }
if (groupList != null) { allGroups.addAll(groupList); }
if (!allGroups.isEmpty()) {
query.taskCandidateGroupIn(allGroups);
} Type guard
boolean canSetCandidateGroupIn(HistoricTaskInstanceQueryImpl q) {
return q.candidateGroup == null; // single group not yet set
} Try / catch
try {
query.taskCandidateGroupIn(groups);
} catch (FlowableIllegalArgumentException e) {
throw new IllegalStateException(
"Query already filters by candidateGroup; remove one of the two group filters", e);
} Prevention
- Use only taskCandidateGroupIn() across the codebase; wrap single groups in singletonList().
- Centralize query building so group criteria cannot be set twice.
- When filters arrive from multiple layers, merge them into one list first.
When it happens
Trigger: Chaining .taskCandidateGroup("backoffice").taskCandidateGroupIn(groups) on the same HistoricTaskInstanceQuery instance.
Common situations: Accumulating filters from multiple sources (a default single-group filter plus a user-selected group list); generic query-building code that sets whichever group criteria it has without clearing the other.
Related errors
- Invalid query usage: cannot set both candidateGroup and…
- Candidate group is null
- Candidate group list is empty
- Candidate group list is null
- Candidate user is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/d3655d8dae546f1d.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/HistoricTaskInstanceQueryImpl.java:1930
this.currentOrQueryObject.candidateGroup = candidateGroup;
} else {
this.candidateGroup = candidateGroup;
}
return this;
}
@Override
public HistoricTaskInstanceQuery 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 (inOrStatement) {
this.currentOrQueryObject.candidateGroups = candidateGroups;
} else {
this.candidateGroups = candidateGroups;
}
return this;
}
@Override
public HistoricTaskInstanceQuery taskInvolvedUser(String involvedUser) {
if (involvedUser == null) {
throw new FlowableIllegalArgumentException("involved user is null");
}
if (inOrStatement) {
this.currentOrQueryObject.involvedUser = involvedUser;View on GitHub (pinned to d6d39ce1c6)