flowable/flowable-engine · error · FlowableIllegalArgumentException

involvedUser is null

Error message

involvedUser is null

What it means

HistoricPlanItemInstanceQuery.involvedUser() requires a non-null user id string. Flowable throws FlowableIllegalArgumentException when null is passed because an involvement filter with null user would produce meaningless SQL. The value is applied either to the main query or the current OR-query object depending on inOrStatement.

Solutions

  1. Pass a valid non-null user id that has an identity link (involvement) on the plan item instance.
  2. Resolve the current user before building the query and fail earlier with a clear application-level message if absent.
  3. Skip the involvedUser filter when no user is available rather than calling it with null.
  4. Verify the user actually has involvement records (identity links) if you get empty results after fixing the null.

Example fix

// before
query.involvedUser(SecurityUtils.getCurrentUserId());

// after
String userId = SecurityUtils.getCurrentUserId();
if (userId != null) {
    query.involvedUser(userId);
} else {
    throw new IllegalStateException("User must be authenticated to query involved plan items");
}
Defensive patterns

Strategy: validation

Validate before calling

String userId = SecurityUtils.getCurrentUserId();
if (userId == null || userId.isEmpty()) {
    throw new IllegalStateException("Authenticated user id is required");
}
query.involvedUser(userId);

Type guard

boolean hasInvolvedUser(HistoricPlanItemInstance p, String userId) {
    return p != null && userId != null && !userId.isEmpty();
}

Try / catch

try {
    query.involvedUser(userId);
} catch (FlowableIllegalArgumentException e) {
    log.warn("Invalid involvedUser filter: {}", e.getMessage());
    // reject request with 400 or re-query without the filter
}

Prevention

When it happens

Trigger: Calling historicPlanItemInstanceQuery.involvedUser(null), typically involvedUser(authenticatedUserId) where the security context has no authenticated user, or involvedUser(params.get("userId")) with a missing request parameter.

Common situations: Building 'my tasks' style history views while the user session expired (userId resolves to null); REST endpoints where the userId path/query param was omitted; background jobs running without an authenticated principal.

Related errors


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

Appendix: source

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

    }
    
    @Override
    public HistoricPlanItemInstanceQuery planItemInstanceExtraValue(String extraValue) {
        if (extraValue == null) {
            throw new FlowableIllegalArgumentException("extraValue is null");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.extraValue = extraValue;
        } else {
            this.extraValue = extraValue;
        }
        return this;
    }
    
    @Override
    public HistoricPlanItemInstanceQuery involvedUser(String involvedUser) {
        if (involvedUser == null) {
            throw new FlowableIllegalArgumentException("involvedUser is null");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.involvedUser = involvedUser;
        } else {
            this.involvedUser = involvedUser;
        }
        return this;
    }
    
    @Override
    public HistoricPlanItemInstanceQuery involvedGroups(Collection<String> involvedGroups) {
        if (involvedGroups == null) {
            throw new FlowableIllegalArgumentException("involvedGroups is null");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.involvedGroups = involvedGroups;
        } else {
            this.involvedGroups = involvedGroups;

View on GitHub (pinned to d6d39ce1c6)