flowable/flowable-engine · error · FlowableIllegalArgumentException

userId is null

Error message

userId is null

What it means

HistoricProcessInstanceQuery.involvedUser(String userId, String identityLinkType) requires a non-null userId. Flowable throws FlowableIllegalArgumentException when userId is null because an identity-link filter without a user is meaningless. Validation is fail-fast at query-build time.

Source

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

            this.activeActivityIds = activityIds;
        }
        return this;
    }

    @Override
    public HistoricProcessInstanceQuery involvedUser(String involvedUser) {
        if (inOrStatement) {
            this.currentOrQueryObject.involvedUser = involvedUser;
        } else {
            this.involvedUser = involvedUser;
        }
        return this;
    }
    
    @Override
    public HistoricProcessInstanceQuery 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) {
            this.currentOrQueryObject.involvedUserIdentityLink = new IdentityLinkQueryObject(userId, null, identityLinkType);
        } else {
            this.involvedUserIdentityLink = new IdentityLinkQueryObject(userId, null, identityLinkType);
        }
        return this;
    }
    
    @Override
    public HistoricProcessInstanceQuery involvedGroup(String groupId, String identityLinkType) {
        if (groupId == null) {
            throw new FlowableIllegalArgumentException("groupId is null");
        }
        if (identityLinkType == null) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Pass a non-null userId string to involvedUser
  2. Null-check the userId first and skip the involvedUser criterion or use a different query when absent
  3. Resolve the user identity upstream (e.g. require authentication) before building the query
  4. If the intent is to query regardless of user, drop this criterion entirely

Example fix

// before
query.involvedUser(userId, IdentityLinkType.PARTICIPANT); // throws when userId == null
// after
if (userId != null) {
    query.involvedUser(userId, IdentityLinkType.PARTICIPANT);
}
Defensive patterns

Strategy: validation

Validate before calling

if (userId == null) {
    throw new IllegalArgumentException("userId is required for involvedUser filter");
}
query.involvedUser(userId, IdentityLinkType.PARTICIPANT);

Type guard

boolean isValidUserId(String userId) {
    return userId != null && !userId.trim().isEmpty();
}

Try / catch

try {
    query.involvedUser(userId, identityLinkType);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().equals("userId is null")) {
        // fall back to a query without the involvedUser criterion
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling involvedUser(null, identityLinkType) — e.g. the userId comes from a nullable authenticated-user context, request parameter, or variable that was never assigned.

Common situations: Web controllers passing SecurityContext-derived usernames that are null for anonymous users; service methods forwarding optional user arguments; refactors that removed a default user value.

Related errors


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