flowable/flowable-engine · error · FlowableIllegalArgumentException

userId is null and groups are null or empty

Error message

userId is null and groups are null or empty

What it means

startableByUserOrGroups in CaseDefinitionQueryImpl throws FlowableIllegalArgumentException with "userId is null and groups are null or empty" when both inputs are effectively empty. The method supports an OR filter (user id and/or group membership); at least one of the two must be provided, otherwise the authorization filter would be undefined.

Solutions

  1. Validate that at least one of userId or a non-empty groups collection exists before calling; otherwise skip the filter or reject the request.
  2. Fix group resolution so membership is fetched (e.g. via identityService) before building the query.
  3. Require authentication earlier in the flow so user id or groups are always available.

Example fix

// before
query.startableByUserOrGroups(userId, groups);

// after
boolean hasUser = userId != null;
boolean hasGroups = groups != null && !groups.isEmpty();
if (hasUser || hasGroups) {
    query.startableByUserOrGroups(userId, groups);
} else {
    throw new SecurityException("user or groups required");
}
Defensive patterns

Strategy: validation

Validate before calling

boolean ok = userId != null || (groups != null && !groups.isEmpty());
if (ok) {
    query.startableByUserOrGroups(userId, groups);
} else {
    throw new SecurityException("userId or groups required");
}

Type guard

boolean hasIdentity(String u, java.util.Collection<String> g) {
    return u != null || (g != null && !g.isEmpty());
}

Try / catch

try {
    query.startableByUserOrGroups(userId, groups);
} catch (FlowableIllegalArgumentException e) {
    if (!e.getMessage().contains("groups are null or empty")) throw e;
    throw new SecurityException("no identity information available");
}

Prevention

When it happens

Trigger: Calling startableByUserOrGroups(null, null) or startableByUserOrGroups(null, Collections.emptyList()) — e.g. when identity resolution returned neither a user nor group memberships.

Common situations: Unauthenticated sessions where user id and groups are both unavailable; a group-fetching service failing silently and returning an empty collection; wiring the wrong (unpopulated) identity object into the query.

Related errors


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

Appendix: source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/repository/CaseDefinitionQueryImpl.java:320

        } else if (authorizationUserId == null) {
            return null;
        }
        return CommandContextUtil.getCmmnEngineConfiguration().getCandidateManager().getGroupsForCandidateUser(authorizationUserId);
    }
    
    @Override
    public CaseDefinitionQuery startableByUser(String userId) {
        if (userId == null) {
            throw new FlowableIllegalArgumentException("userId is null");
        }
        this.authorizationUserId = userId;
        return this;
    }

    @Override
    public CaseDefinitionQuery startableByUserOrGroups(String userId, Collection<String> groups) {
        if (userId == null && (groups == null || groups.isEmpty())) {
            throw new FlowableIllegalArgumentException("userId is null and groups are null or empty");
        }
        this.authorizationUserId = userId;
        this.authorizationGroups = groups;
        this.authorizationGroupsSet = true;
        return this;
    }

    // sorting ////////////////////////////////////////////

    @Override
    public CaseDefinitionQuery orderByDeploymentId() {
        return orderBy(CaseDefinitionQueryProperty.CASE_DEFINITION_DEPLOYMENT_ID);
    }

    @Override
    public CaseDefinitionQuery orderByCaseDefinitionKey() {
        return orderBy(CaseDefinitionQueryProperty.CASE_DEFINITION_KEY);
    }

View on GitHub (pinned to d6d39ce1c6)