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

  1. Provide a non-null userId and/or a non-empty groups collection
  2. Fail earlier if the authenticated identity is unavailable
  3. 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

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


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)