flowable/flowable-engine · error · FlowableIllegalArgumentException
at least one of userId or groups must be provided
Error message
at least one of userId or groups must be provided
What it means
ExternalWorkerJobQueryImpl.forUserOrGroups(String userId, Collection<String> groups) requires at least one non-null identity: either a userId or a non-empty groups collection. Calling it with userId == null and groups == null/empty yields FlowableIllegalArgumentException. It sets the authorizedUser/authorizedGroups filters used for permission-scoped external worker job queries.
Solutions
- Pass at least the current user's id, e.g. forUserOrGroups(userId, userGroups)
- If neither is available, do not call forUserOrGroups() and decide explicitly whether the query should be unscoped (and whether that is allowed)
- Validate inputs before the call and return a domain-level 'identity filter required' error
- Check that group resolution (e.g. from identity service) actually returns members
Example fix
// before
query.forUserOrGroups(userId, groups); // both may be empty
// after
boolean hasGroups = groups != null && !groups.isEmpty();
if (userId != null || hasGroups) {
query.forUserOrGroups(userId, groups);
} else {
throw new IllegalArgumentException("Identity filter required");
} Defensive patterns
Strategy: validation
Validate before calling
boolean hasUser = userId != null;
boolean hasGroups = groups != null && !groups.isEmpty();
if (!hasUser && !hasGroups) {
throw new IllegalArgumentException("Provide userId or groups for forUserOrGroups");
}
externalWorkerJobQuery.forUserOrGroups(userId, groups); Type guard
boolean hasIdentity(String userId, Collection<String> groups) {
return userId != null || (groups != null && !groups.isEmpty());
} Prevention
- Make identity filters mandatory in UI/API layers that feed this query
- Check group-resolution results for emptiness before querying
- Decide explicitly between unscoped and identity-scoped queries
When it happens
Trigger: Calling forUserOrGroups(null, null), forUserOrGroups(null, Collections.emptyList()), or with a groups collection that was filtered down to empty at runtime.
Common situations: Permission-aware dashboards where both user and group filters are optional in the UI but mandatory in the query API; dynamic group lists emptied by prior filtering.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/db691ccd27184443.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/ExternalWorkerJobQueryImpl.java:505
this.tenantIdLike = tenantIdLike;
}
return this;
}
@Override
public ExternalWorkerJobQuery jobWithoutTenantId() {
if (inOrStatement) {
this.currentOrQueryObject.withoutTenantId = true;
} else {
this.withoutTenantId = true;
}
return this;
}
@Override
public ExternalWorkerJobQuery forUserOrGroups(String userId, Collection<String> groups) {
if (userId == null && (groups == null || groups.isEmpty())) {
throw new FlowableIllegalArgumentException("at least one of userId or groups must be provided");
}
if (inOrStatement) {
this.currentOrQueryObject.authorizedUser = userId;
this.currentOrQueryObject.authorizedGroups = groups;
} else {
this.authorizedUser = userId;
this.authorizedGroups = groups;
}
return this;
}
@Override
public ExternalWorkerJobQuery lockOwner(String lockOwner) {
if (inOrStatement) {
this.currentOrQueryObject.lockOwner = lockOwner;
} else {View on GitHub (pinned to d6d39ce1c6)