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
- Validate that at least one of userId or a non-empty groups collection exists before calling; otherwise skip the filter or reject the request.
- Fix group resolution so membership is fetched (e.g. via identityService) before building the query.
- 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
- Fetch group memberships before building the query
- Fail fast on unauthenticated requests rather than passing nulls through
- Encapsulate user-or-groups resolution in one utility with a non-empty guarantee
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
- userId is null
- callback id is null
- callbackId is null
- case definition tenantId is null
- caseDefinition tenantId is null
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)