flowable/flowable-engine · error · FlowableIllegalArgumentException

involvedGroups are null

Error message

involvedGroups are null

What it means

HistoricProcessInstanceQuery.involvedGroups(Set<String>) requires a non-null set of group ids. Flowable throws FlowableIllegalArgumentException when involvedGroups is null, preventing an undefined IN filter on group identity links. The check runs eagerly when building the query.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/HistoricProcessInstanceQueryImpl.java:638

    public HistoricProcessInstanceQuery 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 HistoricProcessInstanceQuery involvedGroups(Set<String> involvedGroups) {
        if (involvedGroups == null) {
            throw new FlowableIllegalArgumentException("involvedGroups are null");
        }
        if (involvedGroups.isEmpty()) {
            throw new FlowableIllegalArgumentException("involvedGroups are empty");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.involvedGroups = involvedGroups;
        } else {
            this.involvedGroups = involvedGroups;
        }
        return this;
    }

    @Override
    public HistoricProcessInstanceQuery includeProcessVariables() {
        this.includeProcessVariables = true;
        return this;
    }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Initialize the set before the call, e.g. Set<String> groups = new HashSet<>(...);
  2. Null-check and skip the criterion or fall back to another filter when null
  3. Use Collections.emptySet() semantics explicitly: only call involvedGroups when groups != null
  4. If the user has no groups, decide the intended result (no filter vs empty result) and code accordingly

Example fix

// before
query.involvedGroups(groups); // throws when groups == null
// after
if (groups != null && !groups.isEmpty()) {
    query.involvedGroups(groups);
}
Defensive patterns

Strategy: validation

Validate before calling

if (groups == null) {
    throw new IllegalArgumentException("involvedGroups must be non-null");
}
if (!groups.isEmpty()) {
    query.involvedGroups(groups);
}

Type guard

boolean isValidGroupSet(Set<String> groups) {
    return groups != null;
}

Try / catch

try {
    query.involvedGroups(groups);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().contains("null")) {
        groups = Collections.emptySet(); // then decide on empty-set behavior
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling involvedGroups(groups) with a null set — e.g. the group set comes from a membership lookup returning null, an uninitialized field, or a nullable request parameter.

Common situations: Authorization-scoped history queries where user group resolution failed; bulk queries built from config that omitted the group list; refactors changing empty-set defaults to null.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/f0f3136f0ad8d651. Report an issue: GitHub.