{"record":{"id":"db691ccd27184443","repo":"flowable/flowable-engine","slug":"at-least-one-of-userid-or-groups-must-be-provided-db691c","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":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/ExternalWorkerJobQueryImpl.java","lineNumber":505,"sourceCode":"            this.tenantIdLike = tenantIdLike;\n        }\n        return this;\n    }\n\n    @Override\n    public ExternalWorkerJobQuery jobWithoutTenantId() {\n        if (inOrStatement) {\n            this.currentOrQueryObject.withoutTenantId = true;\n        } else {\n            this.withoutTenantId = true;\n        }\n        return this;\n    }\n\n    @Override\n    public ExternalWorkerJobQuery 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        if (inOrStatement) {\n            this.currentOrQueryObject.authorizedUser = userId;\n            this.currentOrQueryObject.authorizedGroups = groups;\n        } else {\n            this.authorizedUser = userId;\n            this.authorizedGroups = groups;\n        }\n\n        return this;\n    }\n\n    @Override\n    public ExternalWorkerJobQuery lockOwner(String lockOwner) {\n        if (inOrStatement) {\n            this.currentOrQueryObject.lockOwner = lockOwner;\n        } else {","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/ExternalWorkerJobQueryImpl.java#L487-L523","documentation":"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.","triggerScenarios":"Calling forUserOrGroups(null, null), forUserOrGroups(null, Collections.emptyList()), or with a groups collection that was filtered down to empty at runtime.","commonSituations":"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.","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"],"exampleFix":"// before\nquery.forUserOrGroups(userId, groups); // both may be empty\n// after\nboolean hasGroups = groups != null && !groups.isEmpty();\nif (userId != null || hasGroups) {\n    query.forUserOrGroups(userId, groups);\n} else {\n    throw new IllegalArgumentException(\"Identity filter required\");\n}","handlingStrategy":"validation","validationCode":"boolean hasUser = userId != null;\nboolean hasGroups = groups != null && !groups.isEmpty();\nif (!hasUser && !hasGroups) {\n    throw new IllegalArgumentException(\"Provide userId or groups for forUserOrGroups\");\n}\nexternalWorkerJobQuery.forUserOrGroups(userId, groups);","typeGuard":"boolean hasIdentity(String userId, Collection<String> groups) {\n    return userId != null || (groups != null && !groups.isEmpty());\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["flowable","null-argument","authorization"],"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"}