{"record":{"id":"e84a24b4ba2020a0","repo":"flowable/flowable-engine","slug":"a-group-or-a-user-is-required-to-create-an-identit","errorCode":null,"errorMessage":"A group or a user is required to create an identity link.","messagePattern":"A group or a user is required to create an identity link\\.","errorType":"http","errorClass":"FlowableIllegalArgumentException","httpStatus":400,"severity":"warning","filePath":"modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/repository/CaseDefinitionIdentityLinkCollectionResource.java","lineNumber":74,"sourceCode":"\n        return restResponseFactory.createRestIdentityLinks(repositoryService.getIdentityLinksForCaseDefinition(caseDefinition.getId()));\n    }\n\n    @ApiOperation(value = \"Add a candidate starter to a case definition\", tags = { \"Case Definitions\" },\n            notes = \"It is possible to add either a user or a group.\", code = 201)\n    @ApiResponses(value = {\n            @ApiResponse(code = 201, message = \"Indicates the case 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 case definition was not found.\")\n    })\n    @PostMapping(value = \"/cmmn-repository/case-definitions/{caseDefinitionId}/identitylinks\", produces = \"application/json\")\n    @ResponseStatus(HttpStatus.CREATED)\n    public RestIdentityLink createIdentityLink(@ApiParam(name = \"caseDefinitionId\") @PathVariable String caseDefinitionId, @RequestBody RestIdentityLink identityLink) {\n\n        CaseDefinition caseDefinition = getCaseDefinitionFromRequestWithoutAccessCheck(caseDefinitionId);\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.createCaseDefinitionIdentityLink(caseDefinition, identityLink);\n        }\n\n        if (identityLink.getGroup() != null) {\n            repositoryService.addCandidateStarterGroup(caseDefinition.getId(), identityLink.getGroup());\n        } else {\n            repositoryService.addCandidateStarterUser(caseDefinition.getId(), identityLink.getUser());\n        }\n\n        // Always candidate for case definition. User-provided value is ignored\n        identityLink.setType(IdentityLinkType.CANDIDATE);","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/repository/CaseDefinitionIdentityLinkCollectionResource.java#L56-L92","documentation":"CaseDefinitionIdentityLinkCollectionResource.createIdentityLink adds an identity link (user or group) to a case definition from a JSON RestIdentityLink body. If neither 'group' nor 'user' is set in the body, the request is meaningless, so it throws FlowableIllegalArgumentException mapped to HTTP 400.","triggerScenarios":"POST /cmmn-repository/case-definitions/{caseDefinitionId}/identity-links with a body like {\"type\":\"candidate\"} lacking both 'user' and 'group' fields.","commonSituations":"Client sends only the link type; JSON property names mismatch the RestIdentityLink fields (e.g. 'userId' instead of 'user') so they deserialize to null; empty payloads from templated request builders.","solutions":["Include either \"user\":\"<userId>\" or \"group\":\"<groupId>\" in the request body.","Check the JSON keys match RestIdentityLink field names exactly (user, group, type).","Validate the payload client-side before posting the identity link."],"exampleFix":"// before\nPOST .../identity-links\n{\"type\":\"candidate\"}\n// after\nPOST .../identity-links\n{\"type\":\"candidate\",\"group\":\"sales\"}","handlingStrategy":"validation","validationCode":"function validateIdentityLink(link) {\n  if (!link.user && !link.group) throw new Error('identity link needs user or group');\n  return true;\n}","typeGuard":"const isValidIdentityLink = (l) => Boolean(l && (typeof l.user === 'string' || typeof l.group === 'string'));","tryCatchPattern":"try {\n  await post(identityLinksUrl, link);\n} catch (e) {\n  if (e.response?.status === 400 && /group or a user/.test(e.response.data?.message)) {\n    throw new Error('Request body must contain \"user\" or \"group\"');\n  }\n  throw e;\n}","preventionTips":["Use field names 'user', 'group', 'type' exactly as RestIdentityLink expects.","Validate payloads before POSTing identity links.","Build payloads from typed models, not free-form objects."],"tags":["rest-api","validation","identity-link"],"backgroundTag":"missing-required-argument","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}