{"record":{"id":"f841d8a7bde3f266","repo":"flowable/flowable-engine","slug":"only-one-of-user-or-group-can-be-used-to-create-an-f841d8","errorCode":null,"errorMessage":"Only one of user or group can be used to create an identity link.","messagePattern":"Only one of user or group can be used to create an identity link\\.","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":400,"severity":"error","filePath":"modules/flowable-rest/src/main/java/org/flowable/rest/service/api/repository/ProcessDefinitionIdentityLinkCollectionResource.java","lineNumber":79,"sourceCode":"            notes = \"It is possible to add either a user or a group.\",\n            code = 201)\n    @ApiResponses(value = {\n            @ApiResponse(code = 201, message = \"Indicates the process definition was found and the identity link was created.\"),\n            @ApiResponse(code = 400, message = \"Indicates the body does not contain the correct information.\"),\n            @ApiResponse(code = 404, message = \"Indicates the requested process definition was not found.\")\n    })\n    @PostMapping(value = \"/repository/process-definitions/{processDefinitionId}/identitylinks\", produces = \"application/json\")\n    @ResponseStatus(HttpStatus.CREATED)\n    public RestIdentityLink createIdentityLink(@ApiParam(name = \"processDefinitionId\") @PathVariable String processDefinitionId, @RequestBody RestIdentityLink identityLink) {\n\n        ProcessDefinition processDefinition = getProcessDefinitionFromRequestWithoutAccessCheck(processDefinitionId);\n\n        if (identityLink.getGroup() == null && identityLink.getUser() == null) {\n            throw new FlowableIllegalArgumentException(\"A group or a user is required to create an identity link.\");\n        }\n\n        if (identityLink.getGroup() != null && identityLink.getUser() != null) {\n            throw new FlowableIllegalArgumentException(\"Only one of user or group can be used to create an identity link.\");\n        }\n\n        if (restApiInterceptor != null) {\n            restApiInterceptor.createProcessDefinitionIdentityLink(processDefinition, identityLink);\n        }\n\n        if (identityLink.getGroup() != null) {\n            repositoryService.addCandidateStarterGroup(processDefinition.getId(), identityLink.getGroup());\n        } else {\n            repositoryService.addCandidateStarterUser(processDefinition.getId(), identityLink.getUser());\n        }\n\n        // Always candidate for process-definition. User-provided value is\n        // ignored\n        identityLink.setType(IdentityLinkType.CANDIDATE);\n\n        return restResponseFactory.createRestIdentityLink(identityLink.getType(), identityLink.getUser(), identityLink.getGroup(), null, processDefinition.getId(), null);\n    }","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/repository/ProcessDefinitionIdentityLinkCollectionResource.java#L61-L97","documentation":"Thrown when creating a process-definition identity link with BOTH a user and a group set. Flowable requires the link to target exactly one principal, so the request is rejected as an invalid argument.","triggerScenarios":"POST identity link with a body containing both fields, e.g. {\"type\":\"candidate\",\"user\":\"kermit\",\"group\":\"sales\"}.","commonSituations":"Client code copying a payload template and forgetting to clear the other field; UI forms submitting both inputs; bulk import scripts mapping both columns unconditionally.","solutions":["Send only one of user or group per request; issue two requests if both are needed","Clear the unused field client-side before serializing the JSON","Add client-side validation that exactly one of user/group is populated"],"exampleFix":"// before\n{\"type\":\"candidate\",\"user\":\"kermit\",\"group\":\"sales\"}\n// after\n{\"type\":\"candidate\",\"group\":\"sales\"}","handlingStrategy":"validation","validationCode":"if (body.getGroup() != null && body.getUser() != null) throw new IllegalArgumentException(\"set only one of user or group\");","typeGuard":null,"tryCatchPattern":"try { createIdentityLink(defId, link); } catch (FlowableIllegalArgumentException e) { /* strip the extra field and resend */ }","preventionTips":["Build payloads from explicit fields, not copy-pasted templates","Null-out the unused field before serializing","Add schema validation that enforces exactly one of user/group"],"tags":["flowable","rest","identity-link","validation"],"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-18T16:30:33.424Z"}