flowable/flowable-engine · error · FlowableIllegalArgumentException

involvedUser is null

Error message

involvedUser is null

What it means

HistoricCaseInstanceQueryImpl.involvedUser(String) throws FlowableIllegalArgumentException when the userId is null. Involvement filtering requires an actual user id to match identity links; a null userId would make the predicate meaningless, so the library validates eagerly.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/HistoricCaseInstanceQueryImpl.java:1082

    }
    
    @Override
    public HistoricCaseInstanceQuery activePlanItemDefinitionIds(Set<String> planItemDefinitionIds) {
        if (planItemDefinitionIds == null) {
            throw new FlowableIllegalArgumentException("planItemDefinitionIds is null");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.activePlanItemDefinitionIds = planItemDefinitionIds;
        } else {
            this.activePlanItemDefinitionIds = planItemDefinitionIds;
        }
        return this;
    }

    @Override
    public HistoricCaseInstanceQuery involvedUser(String userId) {
        if (userId == null) {
            throw new FlowableIllegalArgumentException("involvedUser is null");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.involvedUser = userId;
        } else {
            this.involvedUser = userId;
        }
        return this;
    }
    
    @Override
    public HistoricCaseInstanceQuery involvedUser(String userId, String identityLinkType) {
        if (userId == null) {
            throw new FlowableIllegalArgumentException("userId is null");
        }
        if (identityLinkType == null) {
            throw new FlowableIllegalArgumentException("identityLinkType is null");
        }
        if (inOrStatement) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Check the userId for null/blank before adding the involvement filter.
  2. Resolve the current user properly and handle the unauthenticated case before building the query.
  3. If involvement is optional, conditionally add the filter only when a user id exists.
  4. Validate upstream REST/REST-call inputs so null never reaches the query builder.

Example fix

// before
query.involvedUser(userId); // userId may be null
// after
if (userId != null && !userId.isEmpty()) {
    query.involvedUser(userId);
}
Defensive patterns

Strategy: validation

Validate before calling

if (userId == null || userId.isEmpty()) {
    throw new IllegalArgumentException("userId is required");
}
query.involvedUser(userId);

Type guard

boolean hasText(String s) {
    return s != null && !s.trim().isEmpty();
}

Try / catch

try {
    query.involvedUser(userId);
} catch (FlowableIllegalArgumentException e) {
    if ("involvedUser is null".equals(e.getMessage())) {
        // handle unauthenticated/anonymous case
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling involvedUser(null) on a HistoricCaseInstanceQuery, directly or inside an or() block, before executing the query.

Common situations: Current-user resolution (e.g. from SecurityContext/authentication) returned null for anonymous requests; a form or REST parameter was optional and bound to null; user id variable lost during refactoring.

Related errors


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