flowable/flowable-engine · error · ActivitiIllegalArgumentException
Candidate group list is null
Error message
Candidate group list is null
What it means
HistoricTaskInstanceQueryImpl.taskCandidateGroupIn(List<String>) rejects a null list with ActivitiIllegalArgumentException. Passing null means no group criterion could be built, so the engine fails fast rather than issuing a malformed query.
Source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/HistoricTaskInstanceQueryImpl.java:1099
throw new ActivitiIllegalArgumentException("Candidate group is null");
}
if (candidateGroups != null) {
throw new ActivitiIllegalArgumentException("Invalid query usage: cannot set both candidateGroup and candidateGroupIn");
}
if (inOrStatement) {
this.currentOrQueryObject.candidateGroup = candidateGroup;
} else {
this.candidateGroup = candidateGroup;
}
return this;
}
@Override
public HistoricTaskInstanceQuery taskCandidateGroupIn(List<String> candidateGroups) {
if (candidateGroups == null) {
throw new ActivitiIllegalArgumentException("Candidate group list is null");
}
if (candidateGroups.isEmpty()) {
throw new ActivitiIllegalArgumentException("Candidate group list is empty");
}
if (candidateGroup != null) {
throw new ActivitiIllegalArgumentException("Invalid query usage: cannot set both candidateGroupIn and candidateGroup");
}
if (inOrStatement) {
this.currentOrQueryObject.candidateGroups = candidateGroups;
} else {
this.candidateGroups = candidateGroups;
}
return this;
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Initialize the list (Collections.emptyList() if you also handle the empty case) before calling, or skip the call when null.
- Make the upstream resolver return an empty list instead of null.
- If the groups are mandatory, fail in your own layer with a clearer error before touching the query.
Example fix
// before
List<String> groups = fetchGroups(tenantId); // may return null
query.taskCandidateGroupIn(groups); // throws when null
// after
List<String> groups = fetchGroups(tenantId);
if (groups != null && !groups.isEmpty()) {
query.taskCandidateGroupIn(groups);
} Defensive patterns
Strategy: validation
Validate before calling
// Java
if (candidateGroups != null && !candidateGroups.isEmpty()) {
query.taskCandidateGroupIn(candidateGroups);
} Try / catch
try {
query.taskCandidateGroupIn(groups);
} catch (org.activiti.engine.ActivitiIllegalArgumentException e) {
// skip filter or propagate a clearer domain error
} Prevention
- Make list-returning resolvers return empty lists, never null.
- Null-check externally sourced group lists at the boundary.
- Initialize filter DTO list fields with empty collections.
When it happens
Trigger: Calling taskCandidateGroupIn(null), e.g. when the group list variable was never initialized or a lookup returned null.
Common situations: Group list fetched from an external source (LDAP, DB, config) that returned null on failure; uninitialized field in a filter DTO passed straight through.
Related errors
- Candidate user is null
- Candidate group is null
- DeploymentId is null
- Error retrieving app engine info
- No deployment id available
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/487fe0dd385b96f0.
Report an issue: GitHub.