flowable/flowable-engine · error · FlowableIllegalArgumentException
Invalid query usage: cannot set both candidateGroup and…
Error message
Invalid query usage: cannot set both candidateGroup and candidateUser
What it means
TaskQueryImpl.taskCandidateOrAssigned() throws this when candidateUser was already set. A task query cannot combine a plain candidateUser filter with the candidateOrAssigned (both candidate and assignee) filter, since their identity-link semantics conflict. Flowable validates this at query build time.
Solutions
- Use taskCandidateOrAssigned() alone when you want candidate-or-assignee semantics; drop the separate taskCandidateUser() call.
- Build a fresh TaskQuery rather than reusing one where candidateUser was previously set.
- Refactor shared query-builder helpers so only one candidate-user-style filter is applied.
- Check or() branch composition to ensure candidateUser and candidateOrAssigned are not both set.
Example fix
// before query.taskCandidateUser(userId); query.taskCandidateOrAssigned(userId); // after query.taskCandidateOrAssigned(userId); // covers candidate and assignee
Defensive patterns
Strategy: validation
Validate before calling
query.taskCandidateOrAssigned(userId); // do not also call taskCandidateUser on the same query
Try / catch
try {
query.taskCandidateOrAssigned(userId);
} catch (FlowableIllegalArgumentException e) {
logger.warn("candidateUser already set: {}", e.getMessage());
query = taskService.createTaskQuery();
} Prevention
- Drop taskCandidateUser() when switching to taskCandidateOrAssigned() semantics
- Never mix candidate filters in the same query or or() branch
- Instantiate fresh TaskQuery objects per request
- Audit query-builder helpers for multiple candidate-setter calls
When it happens
Trigger: Calling taskQuery.taskCandidateOrAssigned(userId) after taskCandidateUser(user), or setting candidateUser inside an or() branch before invoking candidateOrAssigned.
Common situations: Incremental query construction where two filters were added; merging code that used candidateUser with code migrated to candidateOrAssigned; reused query objects carrying state.
Related errors
- Invalid query usage: cannot set both candidateGroup and…
- Invalid query usage: cannot set both candidateGroupIn and…
- Invalid query usage: cannot set both candidateGroup and…
- Invalid query usage: cannot set both candidateGroupIn 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/30c4025d2c2c75be.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/TaskQueryImpl.java:643
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");
}
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");
}View on GitHub (pinned to d6d39ce1c6)