flowable/flowable-engine · error · ActivitiIllegalArgumentException
Invalid query usage: cannot set both candidateGroup and…
Error message
Invalid query usage: cannot set both candidateGroup and candidateUser
What it means
taskCandidateOrAssigned(String userIdForCandidateAndAssignee) throws this error when candidateUser has already been set via taskCandidateUser(...). taskCandidateOrAssigned already includes candidate-user semantics, so combining it with taskCandidateUser would duplicate/conflict the identity-link conditions. Use one or the other.
Solutions
- Remove the taskCandidateUser call and rely on taskCandidateOrAssigned alone
- If both semantics are truly needed, issue separate queries and union the results in application code
- Add a builder/validation layer that asserts only one candidate-filter mode is configured
Example fix
// before
query.taskCandidateUser("kermit");
query.taskCandidateOrAssigned("kermit"); // throws
// after
query.taskCandidateOrAssigned("kermit"); Defensive patterns
Strategy: validation
Validate before calling
if (candidateUser != null && candidateOrAssignedUser != null) {
throw new IllegalStateException("taskCandidateOrAssigned already covers candidate-user semantics");
} Try / catch
try {
query.taskCandidateOrAssigned(userId);
} catch (ActivitiIllegalArgumentException e) {
log.warn("candidateUser already set: {}", e.getMessage());
query = taskService.createTaskQuery().taskCandidateUser(candidateUser);
} Prevention
- Prefer taskCandidateOrAssigned when you want claimed + unclaimed tasks for a user
- Remove legacy taskCandidateUser calls when migrating to candidate-or-assigned
- Assert single candidate-filter mode in a query-builder wrapper
When it happens
Trigger: Calling taskQuery.taskCandidateOrAssigned(userId) after taskQuery.taskCandidateUser(someUser) on the same query (or within the same OR block) - checked at TaskQueryImpl.java:535.
Common situations: Query composition layers that add a candidate-user filter while a newer code path switched to candidate-or-assigned; refactoring a task list to show claimed+unclaimed tasks but leaving the old candidateUser call; copy-pasted OR query blocks.
Related errors
- Candidate user is null
- Invalid query usage: cannot set both candidateGroupIn and…
- Invalid query usage: cannot set both candidateGroup and…
- Invalid query usage: cannot set both candidateGroup and…
- Invalid query usage: cannot set both taskNameInIgnoreCase…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/f194a97aaf91454b.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/TaskQueryImpl.java:535
if (candidateGroups != null) {
throw new ActivitiIllegalArgumentException("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 ActivitiIllegalArgumentException("Invalid query usage: cannot set candidateGroup");
}
if (candidateUser != null) {
throw new ActivitiIllegalArgumentException("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(List<String> candidateGroups) {
if (candidateGroups == null) {
throw new ActivitiIllegalArgumentException("Candidate group list is null");
}View on GitHub (pinned to d6d39ce1c6)