flowable/flowable-engine · error · FlowableIllegalArgumentException
Involved groups are null
Error message
Involved groups are null
What it means
ProcessInstanceQuery.involvedGroups(Set<String>) requires a non-null set of group ids; Flowable throws FlowableIllegalArgumentException("Involved groups are null") when the set is null (and a companion error when it is empty). It validates the bulk involved-groups criterion before executing.
Solutions
- Ensure a non-null Set is passed, e.g. involvedGroups(Collections.emptySet()) when there are no groups (but note empty also throws — skip the call instead)
- Default to an empty set and conditionally apply the criterion only when groups are present and non-empty
- Fix the upstream producer so the group set is initialized before query construction
Example fix
// before
query.involvedGroups(filter.getGroups()); // may be null
// after
Set<String> groups = filter.getGroups();
if (groups != null && !groups.isEmpty()) {
query.involvedGroups(groups);
} Defensive patterns
Strategy: validation
Validate before calling
if (involvedGroups == null || involvedGroups.isEmpty()) {
// skip criterion entirely; involvedGroups rejects null AND empty
return baseQuery;
} Type guard
boolean hasGroups = involvedGroups != null && !involvedGroups.isEmpty();
Try / catch
try {
query.involvedGroups(groups);
} catch (FlowableIllegalArgumentException e) {
if (e.getMessage().contains("Involved groups are")) {
log.warn("Skipping involvedGroups filter: null or empty set");
} else {
throw e;
}
} Prevention
- Initialize group sets to an empty Set at declaration, never null
- Check both null and isEmpty before applying the criterion
- Validate request/filter DTOs so missing 'groups' fields become empty sets
When it happens
Trigger: Calling involvedGroups(null), or passing a set-producing method whose result is null (e.g. map.get("groups"), a cache miss, or an optional that was unwrapped unsafely).
Common situations: Building filters from user-supplied request parameters where the groups parameter was absent; deserialization of a filter JSON that lacked the groups key; migrating from involvedGroup loops to the batch involvedGroups API and passing an unpopulated variable.
Related errors
- Provided batch id is null
- Provided batch type is null
- Provided batch types must be provided and not empty
- Provided correlationId is null
- Provided exception message is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/8935ecadbbf78973.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/ProcessInstanceQueryImpl.java:619
public ProcessInstanceQuery involvedGroup(String groupId, String identityLinkType) {
if (groupId == null) {
throw new FlowableIllegalArgumentException("groupId is null");
}
if (identityLinkType == null) {
throw new FlowableIllegalArgumentException("identityLinkType is null");
}
if (inOrStatement) {
this.currentOrQueryObject.involvedGroupIdentityLink = new IdentityLinkQueryObject(null, groupId, identityLinkType);
} else {
this.involvedGroupIdentityLink = new IdentityLinkQueryObject(null, groupId, identityLinkType);
}
return this;
}
@Override
public ProcessInstanceQuery involvedGroups(Set<String> involvedGroups) {
if (involvedGroups == null) {
throw new FlowableIllegalArgumentException("Involved groups are null");
}
if (involvedGroups.isEmpty()) {
throw new FlowableIllegalArgumentException("Involved groups are empty");
}
if (inOrStatement) {
this.currentOrQueryObject.involvedGroups = involvedGroups;
} else {
this.involvedGroups = involvedGroups;
}
return this;
}
@Override
public ProcessInstanceQuery active() {
if (inOrStatement) {
this.currentOrQueryObject.suspensionState = SuspensionState.ACTIVE;
} else {View on GitHub (pinned to d6d39ce1c6)