{"record":{"id":"a9cdcb501716a438","repo":"flowable/flowable-engine","slug":"a-group-with-id-already-exists","errorCode":null,"errorMessage":"A group with id '' already exists.","messagePattern":"A group with id '' already exists\\.","errorType":"http","errorClass":"FlowableConflictException","httpStatus":409,"severity":"error","filePath":"modules/flowable-rest/src/main/java/org/flowable/rest/service/api/identity/GroupCollectionResource.java","lineNumber":133,"sourceCode":"    @ApiOperation(value = \"Create a group\", tags = { \"Groups\" }, code = 201)\n    @ApiResponses(value = {\n            @ApiResponse(code = 201, message = \"Indicates the group was created.\"),\n            @ApiResponse(code = 400, message = \"Indicates the id of the group was missing.\")\n    })\n    @PostMapping(value = \"/identity/groups\", produces = \"application/json\")\n    @ResponseStatus(HttpStatus.CREATED)\n    public GroupResponse createGroup(@RequestBody GroupRequest groupRequest) {\n        if (groupRequest.getId() == null) {\n            throw new FlowableIllegalArgumentException(\"Id cannot be null.\");\n        }\n        \n        if (restApiInterceptor != null) {\n            restApiInterceptor.createGroup(groupRequest);\n        }\n\n        // Check if a user with the given ID already exists so we return a CONFLICT\n        if (identityService.createGroupQuery().groupId(groupRequest.getId()).count() > 0) {\n            throw new FlowableConflictException(\"A group with id '\" + groupRequest.getId() + \"' already exists.\");\n        }\n\n        Group created = identityService.newGroup(groupRequest.getId());\n        created.setId(groupRequest.getId());\n        created.setName(groupRequest.getName());\n        created.setType(groupRequest.getType());\n        identityService.saveGroup(created);\n\n        return restResponseFactory.createGroupResponse(created);\n    }\n\n}\n","sourceCodeStart":115,"sourceCodeEnd":146,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/identity/GroupCollectionResource.java#L115-L146","documentation":"createGroup checks identityService.createGroupQuery().groupId(id).count() before creating, and throws FlowableConflictException when a group with that id already exists. This pre-check exists because the underlying identity API does not throw a typed duplicate-key exception, so the REST layer maps it to HTTP 409.","triggerScenarios":"POST /identity/groups with an \"id\" that already exists in ACT_ID_GROUP, including a retry of a successful create or a re-seeded demo group id such as from the Flowable demo data setup.","commonSituations":"Non-idempotent bootstrap/seed scripts run twice; race between two admins creating the same group concurrently; migration script re-inserting groups from an old system without checking existence.","solutions":["Check existence first (GET /identity/groups/{id}) and skip or update instead of POSTing a duplicate.","Make seed scripts idempotent: create only when the group is absent.","If the existing group should receive new attributes, use PUT /identity/groups/{id} rather than POST."],"exampleFix":"// before\nclient.post(\"/identity/groups\", group); // may 409 on retry\n// after\nif (client.get(\"/identity/groups/\" + group.getId()) == null) {\n    client.post(\"/identity/groups\", group);\n} else {\n    client.put(\"/identity/groups/\" + group.getId(), group);\n}","handlingStrategy":"validation","validationCode":"boolean exists = client.list(\"/identity/groups\").stream()\n    .anyMatch(g -> groupRequest.getId().equals(g.getId()));\nif (exists) { /* update or skip instead of POST */ }","typeGuard":null,"tryCatchPattern":"try {\n    client.post(\"/identity/groups\", groupRequest);\n} catch (HttpClientErrorException e) {\n    if (e.getStatusCode() == HttpStatus.CONFLICT) {\n        client.put(\"/identity/groups/\" + groupRequest.getId(), groupRequest); // upsert\n    } else throw e;\n}","preventionTips":["Make bootstrap/seed scripts idempotent.","Use PUT for attribute updates, POST only for creation.","Serialize concurrent group creation behind a single admin workflow."],"tags":["rest-api","conflict","group","duplicate"],"backgroundTag":"file-already-exists","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"}