flowable/flowable-engine · error · FlowableIllegalArgumentException

involvedUser is null

Error message

involvedUser is null

What it means

CaseInstanceQueryImpl.involvedUser(String) throws FlowableIllegalArgumentException when the userId argument is null. Flowable validates query parameters at query-construction time because a null involved user cannot be translated into a meaningful SQL filter on the identity-link join.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/CaseInstanceQueryImpl.java:812

    }
    
    @Override
    public CaseInstanceQuery 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 CaseInstanceQuery 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 CaseInstanceQuery 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 invoking involvedUser and skip the filter when absent.
  2. Fix the upstream source of the userId (auth context, request param parsing) so it is always populated when this filter is used.
  3. For an anonymous search, use a different query path that does not involve involvement filtering.
  4. Log and reject the request early with a clear 'involved user required' validation message.

Example fix

// before
query.involvedUser(request.getUserId());
// after
if (request.getUserId() != null && !request.getUserId().isBlank()) {
    query.involvedUser(request.getUserId());
}
Defensive patterns

Strategy: validation

Validate before calling

if (userId == null || userId.isBlank()) {
    throw new IllegalArgumentException("involvedUser must not be null or blank");
}
query.involvedUser(userId);

Type guard

boolean hasUser(String userId) {
    return userId != null && !userId.isBlank();
}

Try / catch

try {
    query.involvedUser(userId);
} catch (FlowableIllegalArgumentException e) {
    log.warn("involvedUser filter skipped: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Calling caseInstanceQuery().involvedUser(null), typically when the userId comes from a variable, request parameter, or security context that was not populated.

Common situations: REST endpoints that pass through an unauthenticated/anonymous user id, spring-security contexts without a principal, or form filters where the 'involved user' field was left blank but the filter is applied unconditionally.

Related errors


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