flowable/flowable-engine · error · FlowableConflictException
User '' is already part of group ''.
Error message
User '' is already part of group ''.
What it means
createMembership first checks via createUserQuery().memberOfGroup(groupId).userId(userId).count() whether the user is already a member, since the underlying identity API does not throw a typed exception for duplicates. If the count is positive it throws FlowableConflictException (HTTP 409).
Solutions
- Check membership first (GET /identity/groups/{groupId}/members) and skip if the user is present.
- Treat HTTP 409 as success in idempotent clients.
- De-duplicate the user list in batch provisioning scripts before calling the API.
Example fix
// before
members.forEach(m -> client.post("/identity/groups/sales/members", m)); // 409 on re-run
// after
Set<String> existing = fetchMemberIds("sales");
members.stream()
.filter(m -> !existing.contains(m.getUserId()))
.forEach(m -> client.post("/identity/groups/sales/members", m)); Defensive patterns
Strategy: validation
Validate before calling
List<String> members = client.list("/identity/groups/" + groupId + "/members")
.stream().map(MembershipResponse::getUserId).collect(Collectors.toList());
if (members.contains(userId)) { /* skip add */ } Try / catch
try {
client.post("/identity/groups/" + groupId + "/members", new MembershipRequest(userId));
} catch (HttpClientErrorException e) {
if (e.getStatusCode() == HttpStatus.CONFLICT) {
log.info("User {} already member of {}", userId, groupId);
} else throw e;
} Prevention
- Treat 409 as success in idempotent provisioning.
- De-duplicate member lists before batch adds.
- Guard double-submits in the UI.
When it happens
Trigger: POST /identity/groups/{groupId}/members where userId is already a member of that group, e.g. retrying a successful membership add or a double-submitted form.
Common situations: Idempotency gaps in provisioning scripts that add users to groups on every run; double-click/double-submit on an 'add member' UI; synchronization job re-adding existing memberships.
Related errors
- A group with id '' already exists.
- Engine property already exists
- Variable ' ' is already present on task ' '.
- Process definition with id '" + processDefinition.getId() +…
- Process instance with id
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/2ac5983acd9866be.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/identity/GroupMembershipCollectionResource.java:59
@ApiResponses(value = {
@ApiResponse(code = 201, message = "Indicates the group was found and the member has been added."),
@ApiResponse(code = 400, message = "Indicates the userId was not included in the request body."),
@ApiResponse(code = 404, message = "Indicates the requested group was not found."),
@ApiResponse(code = 409, message = "Indicates the requested user is already a member of the group.")
})
@PostMapping(value = "/identity/groups/{groupId}/members", produces = "application/json")
@ResponseStatus(HttpStatus.CREATED)
public MembershipResponse createMembership(@ApiParam(name = "groupId") @PathVariable String groupId, @RequestBody MembershipRequest memberShip) {
Group group = getGroupFromRequest(groupId);
if (memberShip.getUserId() == null) {
throw new FlowableIllegalArgumentException("UserId cannot be null.");
}
// Check if user is member of group since API does not return typed exception
if (identityService.createUserQuery().memberOfGroup(group.getId()).userId(memberShip.getUserId()).count() > 0) {
throw new FlowableConflictException("User '" + memberShip.getUserId() + "' is already part of group '" + group.getId() + "'.");
}
identityService.createMembership(memberShip.getUserId(), group.getId());
return restResponseFactory.createMembershipResponse(memberShip.getUserId(), group.getId());
}
}
View on GitHub (pinned to d6d39ce1c6)