{"record":{"id":"c3f28f53db073520","repo":"flowable/flowable-engine","slug":"cannot-assign-a-groupid-to-a-task-assignment-that-c3f28f","errorCode":null,"errorMessage":"Cannot assign a groupId to a task assignment that already has a userId","messagePattern":"Cannot assign a groupId to a task assignment that already has a userId","errorType":"validation","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-identitylink-service/src/main/java/org/flowable/identitylink/service/impl/persistence/entity/IdentityLinkEntityImpl.java","lineNumber":142,"sourceCode":"    }\n\n    @Override\n    public void setUserId(String userId) {\n        if (this.groupId != null && userId != null) {\n            throw new FlowableException(\"Cannot assign a userId to a task assignment that already has a groupId\");\n        }\n        this.userId = userId;\n    }\n\n    @Override\n    public String getGroupId() {\n        return groupId;\n    }\n\n    @Override\n    public void setGroupId(String groupId) {\n        if (this.userId != null && groupId != null) {\n            throw new FlowableException(\"Cannot assign a groupId to a task assignment that already has a userId\");\n        }\n        this.groupId = groupId;\n    }\n\n    @Override\n    public String getTaskId() {\n        return taskId;\n    }\n\n    @Override\n    public void setTaskId(String taskId) {\n        this.taskId = taskId;\n    }\n\n    @Override\n    public String getProcessInstanceId() {\n        return processInstanceId;\n    }","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-identitylink-service/src/main/java/org/flowable/identitylink/service/impl/persistence/entity/IdentityLinkEntityImpl.java#L124-L160","documentation":"IdentityLinkEntityImpl.setGroupId is the counterpart guard: assigning a non-null groupId when userId is already set throws this FlowableException. A runtime identity link must model either a user assignment or a group assignment, not both.","triggerScenarios":"getDefaultIdentityLinks or custom code calling setGroupId on an IdentityLinkEntity whose userId is already non-null, e.g. converting a candidate-user link to a candidate-group link in place.","commonSituations":"Task definitions with overlapping candidateUser/candidateGroup configuration feeding one link; custom assignment listeners reusing an existing link entity; tests constructing links with both fields set.","solutions":["Create separate identity links for user and group assignments.","Call setUserId(null) before setting a groupId if converting the link type is intentional.","Fix the source configuration (BPMN candidate settings or assignment handler) so user and group targets never land on the same entity."],"exampleFix":"// before\nidentityLink.setUserId(\"kermit\");\nidentityLink.setGroupId(\"sales\"); // throws\n\n// after\nidentityLink.setUserId(null);\nidentityLink.setGroupId(\"sales\");","handlingStrategy":"validation","validationCode":"if (identityLink.getUserId() != null && groupId != null) {\n    throw new IllegalArgumentException(\"Split user and group into separate identity links\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    identityLink.setGroupId(groupId);\n} catch (FlowableException e) {\n    // fall back to creating a fresh IdentityLinkEntity for the group\n}","preventionTips":["Clear userId before converting a link to a group assignment.","Verify custom assignment listeners do not mutate an existing user link with a group."],"tags":["identitylink","assignment","invariant","runtime"],"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"}