{"record":{"id":"735b54139841cb20","repo":"flowable/flowable-engine","slug":"groupids-are-empty","errorCode":null,"errorMessage":"groupIds are empty","messagePattern":"groupIds are empty","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/HistoricCaseInstanceQueryImpl.java","lineNumber":1130,"sourceCode":"        }\n        if (identityLinkType == null) {\n            throw new FlowableIllegalArgumentException(\"identityLinkType is null\");\n        }\n        if (inOrStatement) {\n            this.currentOrQueryObject.involvedGroupIdentityLink = new IdentityLinkQueryObject(null, groupId, identityLinkType);\n        } else {\n            this.involvedGroupIdentityLink = new IdentityLinkQueryObject(null, groupId, identityLinkType);\n        }\n        return this;\n    }\n\n    @Override\n    public HistoricCaseInstanceQuery involvedGroups(Set<String> groupIds) {\n        if (groupIds == null) {\n            throw new FlowableIllegalArgumentException(\"groupIds are null\");\n        }\n        if (groupIds.isEmpty()) {\n            throw new FlowableIllegalArgumentException(\"groupIds are empty\");\n        }\n        if (inOrStatement) {\n            this.currentOrQueryObject.involvedGroups = groupIds;\n        } else {\n            this.involvedGroups = groupIds;\n        }\n        return this;\n    }\n\n    @Override\n    public HistoricCaseInstanceQuery or() {\n        if (inOrStatement) {\n            throw new FlowableException(\"the query is already in an or statement\");\n        }\n\n        inOrStatement = true;\n        if (commandContext != null) {\n            currentOrQueryObject = new HistoricCaseInstanceQueryImpl(commandContext, cmmnEngineConfiguration);","sourceCodeStart":1112,"sourceCodeEnd":1148,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/HistoricCaseInstanceQueryImpl.java#L1112-L1148","documentation":"HistoricCaseInstanceQueryImpl.involvedGroups(Set<String>) throws FlowableIllegalArgumentException(\"groupIds are empty\") when the set is non-null but has no elements. An empty IN-clause would be invalid SQL or silently match nothing, so the library rejects it explicitly — the null check at HistoricCaseInstanceQueryImpl.java:1127 handles null, and the isEmpty check at line 1130 handles empty sets.","triggerScenarios":"Calling involvedGroups(new HashSet<>()) or involvedGroups(Set.of()) — i.e. any empty set — on a HistoricCaseInstanceQuery before execution.","commonSituations":"User belongs to no groups so the membership lookup legitimately returns an empty set; filtering groups by tenant/role yielded zero matches; code unconditionally adds the filter without checking membership results.","solutions":["Check groupIds.isEmpty() before calling involvedGroups and skip the filter when empty.","Fall back to another criterion (e.g. involvedUser) when the user has no group memberships.","Decide the intended semantics: an empty set likely means 'no restriction', so omit the filter.","Guard shared query-builder helpers so they never pass empty collections into involvedGroups."],"exampleFix":"// before\nquery.involvedGroups(groupIds); // groupIds may be empty\n// after\nif (groupIds != null && !groupIds.isEmpty()) {\n    query.involvedGroups(groupIds);\n} else {\n    // skip group involvement filter or apply alternate criteria\n}","handlingStrategy":"validation","validationCode":"if (groupIds == null || groupIds.isEmpty()) {\n    // skip the group involvement filter entirely\n    return query;\n}\nquery.involvedGroups(groupIds);","typeGuard":"boolean shouldApplyGroupFilter(Set<String> s) {\n    return s != null && !s.isEmpty();\n}","tryCatchPattern":"try {\n    query.involvedGroups(groupIds);\n} catch (FlowableIllegalArgumentException e) {\n    if (\"groupIds are empty\".equals(e.getMessage())) {\n        // proceed without the group filter or apply alternate criteria\n    } else {\n        throw e;\n    }\n}","preventionTips":["Always guard against both null AND empty before involvedGroups","Decide semantics for empty membership (no filter vs. no results) up front","Prefer skipping the filter when the user has no groups","Cover empty-collection cases in query-builder unit tests"],"tags":["java","flowable","cmmn","query","empty-collection","identity-link"],"backgroundTag":"empty-required-field","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}