{"record":{"id":"052f40967134606a","repo":"flowable/flowable-engine","slug":"invalid-query-usage-cannot-set-both-candidategrou-052f40","errorCode":null,"errorMessage":"Invalid query usage: cannot set both candidateGroupIn and candidateGroup","messagePattern":"Invalid query usage: cannot set both candidateGroupIn and candidateGroup","errorType":"validation","errorClass":"ActivitiIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/TaskQueryImpl.java","lineNumber":560,"sourceCode":"            this.bothCandidateAndAssigned = true;\n            this.userIdForCandidateAndAssignee = userIdForCandidateAndAssignee;\n        }\n\n        return this;\n    }\n\n    @Override\n    public TaskQuery taskCandidateGroupIn(List<String> candidateGroups) {\n        if (candidateGroups == null) {\n            throw new ActivitiIllegalArgumentException(\"Candidate group list is null\");\n        }\n\n        if (candidateGroups.isEmpty()) {\n            throw new ActivitiIllegalArgumentException(\"Candidate group list is empty\");\n        }\n\n        if (candidateGroup != null) {\n            throw new ActivitiIllegalArgumentException(\"Invalid query usage: cannot set both candidateGroupIn and candidateGroup\");\n        }\n\n        if (orActive) {\n            currentOrQueryObject.candidateGroups = candidateGroups;\n        } else {\n            this.candidateGroups = candidateGroups;\n        }\n        return this;\n    }\n\n    @Override\n    public TaskQuery taskTenantId(String tenantId) {\n        if (tenantId == null) {\n            throw new ActivitiIllegalArgumentException(\"task tenant id is null\");\n        }\n        if (orActive) {\n            currentOrQueryObject.tenantId = tenantId;\n        } else {","sourceCodeStart":542,"sourceCodeEnd":578,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/TaskQueryImpl.java#L542-L578","documentation":"TaskQueryImpl throws ActivitiIllegalArgumentException when both taskCandidateGroup(String) (candidateGroup) and taskCandidateGroupIn(List<String>) (candidateGroups) have been set on the same query. The two filters are mutually exclusive: one targets a single group, the other a set, and combining them would produce ambiguous semantics.","triggerScenarios":"Calling taskQuery.taskCandidateGroup(\"hr\") and then taskQuery.taskCandidateGroupIn(groups) (or vice versa) on the same TaskQuery instance, e.g. when filter options are applied additively from request parameters.","commonSituations":"Generic query-builder code that applies every non-null request field; a UI allowing both 'group' and 'any of groups' inputs without making them mutually exclusive; copying an existing query object and adding new filters.","solutions":["Make the two options mutually exclusive in the caller: apply candidateGroup only when candidateGroups is absent, and vice versa (if/else, not both).","Reset or create a fresh TaskQuery instance when the filter mode changes.","Catch ActivitiIllegalArgumentException and map it to a 400 response telling the client to send only one group filter."],"exampleFix":"// before\nquery.taskCandidateGroup(request.getGroup());\nquery.taskCandidateGroupIn(request.getGroups());\n\n// after\nif (request.getGroup() != null) {\n    query.taskCandidateGroup(request.getGroup());\n} else if (request.getGroups() != null && !request.getGroups().isEmpty()) {\n    query.taskCandidateGroupIn(request.getGroups());\n}","handlingStrategy":"validation","validationCode":"if (group != null && groups != null) {\n    throw new IllegalArgumentException(\"Use either candidateGroup or candidateGroupIn, not both\");\n}","typeGuard":"boolean hasExactlyOneGroupFilter(String group, List<String> groups) { return (group == null) != (groups == null); }","tryCatchPattern":"try {\n    return taskQuery.list();\n} catch (ActivitiIllegalArgumentException e) {\n    throw new BadRequestException(\"Send only one of 'group' or 'groups' filters\");\n}","preventionTips":["Enforce mutual exclusivity in the API layer (single 'group filter' field with a mode)","Never apply all non-null request fields additively to a query","Document that candidateGroup and candidateGroupIn cannot be combined"],"tags":["activiti","flowable","task-query","mutually-exclusive"],"backgroundTag":"mutually-exclusive-options","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"}