{"record":{"id":"82506192539d658d","repo":"flowable/flowable-engine","slug":"invalid-query-usage-cannot-set-both-candidategrou-825061","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/HistoricTaskInstanceQueryImpl.java","lineNumber":1107,"sourceCode":"            this.currentOrQueryObject.candidateGroup = candidateGroup;\n        } else {\n            this.candidateGroup = candidateGroup;\n        }\n        return this;\n    }\n\n    @Override\n    public HistoricTaskInstanceQuery 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 (inOrStatement) {\n            this.currentOrQueryObject.candidateGroups = candidateGroups;\n        } else {\n            this.candidateGroups = candidateGroups;\n        }\n        return this;\n    }\n\n    @Override\n    public HistoricTaskInstanceQuery taskInvolvedUser(String involvedUser) {\n        if (inOrStatement) {\n            this.currentOrQueryObject.involvedUser = involvedUser;\n        } else {\n            this.involvedUser = involvedUser;\n        }\n        return this;","sourceCodeStart":1089,"sourceCodeEnd":1125,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/HistoricTaskInstanceQueryImpl.java#L1089-L1125","documentation":"HistoricTaskInstanceQueryImpl.candidateGroupIn() throws ActivitiIllegalArgumentException when candidateGroup was already set on the query. The two filters are mutually exclusive: candidateGroup matches one group, candidateGroupIn matches a list. The query builder refuses to combine them because the persisted query would be ambiguous.","triggerScenarios":"Calling query.taskCandidateGroup(\"hr\") earlier in the fluent chain and later calling query.taskCandidateGroupIn(Arrays.asList(\"hr\",\"sales\")) (or the reverse via internal ordering) on the same HistoricTaskInstanceQuery.","commonSituations":"Building queries programmatically where filter criteria come from user input or config, so both the single-group and group-list variants get applied; refactoring code from candidateGroup to candidateGroupIn while leaving the old call in place.","solutions":["Remove the taskCandidateGroup(...) call and keep only taskCandidateGroupIn(...) (or vice versa)","If you need the single group plus others, add it to the list passed to taskCandidateGroupIn","If both filters are genuinely needed, build two separate queries or use or() scopes appropriately"],"exampleFix":"// before\nquery.taskCandidateGroup(\"hr\");\nquery.taskCandidateGroupIn(Arrays.asList(\"sales\", \"support\"));\n// after\nquery.taskCandidateGroupIn(Arrays.asList(\"hr\", \"sales\", \"support\"));","handlingStrategy":"validation","validationCode":"if (candidateGroup != null && candidateGroups != null) {\n    throw new IllegalArgumentException(\"Use either candidateGroup or candidateGroupIn, not both\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    query.taskCandidateGroupIn(groups);\n} catch (ActivitiIllegalArgumentException e) {\n    if (e.getMessage().contains(\"cannot set both\")) { /* drop one filter and rebuild */ }\n}","preventionTips":["Decide once per query whether the filter is single-group or multi-group","Centralize task-candidate filter building in one helper","Add a unit test asserting only one candidate filter is applied"],"tags":["query","validation","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"}