{"record":{"id":"a63f3403edb5124b","repo":"flowable/flowable-engine","slug":"at-least-one-of-userid-or-groups-must-be-provided","errorCode":null,"errorMessage":"at least one of userId or groups must be provided","messagePattern":"at least one of userId or groups must be provided","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/ExternalWorkerJobAcquireBuilderImpl.java","lineNumber":103,"sourceCode":"        return scopeType(ScopeTypes.CMMN);\n    }\n\n    @Override\n    public ExternalWorkerJobAcquireBuilder scopeType(String scopeType) {\n        this.scopeType = scopeType;\n        return this;\n    }\n\n    @Override\n    public ExternalWorkerJobAcquireBuilder tenantId(String tenantId) {\n        this.tenantId = tenantId;\n        return this;\n    }\n\n    @Override\n    public ExternalWorkerJobAcquireBuilder forUserOrGroups(String userId, Collection<String> groups) {\n        if (userId == null && (groups == null || groups.isEmpty())) {\n            throw new FlowableIllegalArgumentException(\"at least one of userId or groups must be provided\");\n        }\n\n        this.authorizedUser = userId;\n        this.authorizedGroups = groups;\n\n        return this;\n    }\n\n    @Override\n    public List<AcquiredExternalWorkerJob> acquireAndLock(int numberOfTasks, String workerId, int numberOfRetries) {\n        while (numberOfRetries > 0) {\n            try {\n                return commandExecutor.execute(new AcquireExternalWorkerJobsCmd(workerId, numberOfTasks, this, jobServiceConfiguration));\n            } catch (FlowableOptimisticLockingException ignored) {\n                // Query for jobs until there is no FlowableOptimisticLockingException\n                // It is potentially possible multiple workers to query in the exact same time\n                numberOfRetries--;\n            }","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/ExternalWorkerJobAcquireBuilderImpl.java#L85-L121","documentation":"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.","triggerScenarios":"Calling builder.forUserOrGroups(null, null) or forUserOrGroups(null, Collections.emptyList()).","commonSituations":"User identity resolved from security context that was empty (anonymous request); groups collection defaulted to empty list when lookup failed.","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"],"exampleFix":"// before\nbuilder.forUserOrGroups(securityContext.getUserId(), securityContext.getGroups());\n// after\nif (securityContext.getUserId() == null && isEmpty(securityContext.getGroups())) {\n    throw new IllegalStateException(\"no identity for job acquisition\");\n}\nbuilder.forUserOrGroups(securityContext.getUserId(), securityContext.getGroups());","handlingStrategy":"validation","validationCode":"if (userId == null && (groups == null || groups.isEmpty())) throw new IllegalArgumentException(\"at least one of userId or groups is required\");","typeGuard":"boolean hasIdentity(String userId, Collection<String> groups) { return userId != null || (groups != null && !groups.isEmpty()); }","tryCatchPattern":"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 */ }","preventionTips":["Resolve identity before starting acquisition","Reject unauthenticated external-worker requests early","Default groups to a validated non-empty collection or fail clearly"],"tags":["flowable","external-worker","null-argument","empty-collection","validation"],"backgroundTag":"missing-required-argument","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}