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
ExternalWorkerJobAcquireBuilderImpl.forUserOrGroups() filters job acquisition by authorized user and/or groups. If both userId is null and groups is null or empty, nothing could ever match, so Flowable throws FlowableIllegalArgumentException.
Solutions
- Provide a non-null userId and/or a non-empty groups collection
- Fail earlier if the authenticated identity is unavailable
- Use a distinct API path for unrestricted acquisition instead of empty identity
Example fix
// before
builder.forUserOrGroups(securityContext.getUserId(), securityContext.getGroups());
// after
if (securityContext.getUserId() == null && isEmpty(securityContext.getGroups())) {
throw new IllegalStateException("no identity for job acquisition");
}
builder.forUserOrGroups(securityContext.getUserId(), securityContext.getGroups()); Defensive patterns
Strategy: validation
Validate before calling
if (userId == null && (groups == null || groups.isEmpty())) throw new IllegalArgumentException("at least one of userId or groups is required"); Type guard
boolean hasIdentity(String userId, Collection<String> groups) { return userId != null || (groups != null && !groups.isEmpty()); } Try / catch
try { builder.forUserOrGroups(userId, groups); } catch (FlowableIllegalArgumentException e) { if (!e.getMessage().contains("at least one of userId or groups")) throw e; /* handle unauthenticated acquisition request */ } Prevention
- Resolve identity before starting acquisition
- Reject unauthenticated external-worker requests early
- Default groups to a validated non-empty collection or fail clearly
When it happens
Trigger: Calling builder.forUserOrGroups(null, null) or forUserOrGroups(null, Collections.emptyList()).
Common situations: User identity resolved from security context that was empty (anonymous request); groups collection defaulted to empty list when lookup failed.
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
- lockDuration is null
- topic is null
- appsDefinitionIds is null
- Business status is null
- callbackIds is null or empty
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/a63f3403edb5124b.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/ExternalWorkerJobAcquireBuilderImpl.java:103
return scopeType(ScopeTypes.CMMN);
}
@Override
public ExternalWorkerJobAcquireBuilder scopeType(String scopeType) {
this.scopeType = scopeType;
return this;
}
@Override
public ExternalWorkerJobAcquireBuilder tenantId(String tenantId) {
this.tenantId = tenantId;
return this;
}
@Override
public ExternalWorkerJobAcquireBuilder 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");
}
this.authorizedUser = userId;
this.authorizedGroups = groups;
return this;
}
@Override
public List<AcquiredExternalWorkerJob> acquireAndLock(int numberOfTasks, String workerId, int numberOfRetries) {
while (numberOfRetries > 0) {
try {
return commandExecutor.execute(new AcquireExternalWorkerJobsCmd(workerId, numberOfTasks, this, jobServiceConfiguration));
} catch (FlowableOptimisticLockingException ignored) {
// Query for jobs until there is no FlowableOptimisticLockingException
// It is potentially possible multiple workers to query in the exact same time
numberOfRetries--;
}View on GitHub (pinned to d6d39ce1c6)