flowable/flowable-engine · warning · FlowableIllegalArgumentException

Only one of user or group can be used to create an identity…

Error message

Only one of user or group can be used to create an identity link.

What it means

REST request validation in TaskIdentityLinkCollectionResource.createIdentityLink: the body supplied both a user and a group for a single identity link; an identity link targets exactly one principal type, so the combination is rejected.

Solutions

  1. Send only one of 'user' or 'group' per request; issue two requests for both
  2. Clear the other field in the form/model before submitting
  3. Split user and group assignments into separate API calls

Example fix

// before
{"type": "candidate", "user": "kermit", "group": "management"}
// after
{"type": "candidate", "user": "kermit"}
// plus a second call
{"type": "candidate", "group": "management"}
Defensive patterns

Strategy: validation

Validate before calling

if (payload.user && payload.group) {
  throw new Error('send only one of user or group per identity link');
}

Try / catch

try { ... } catch (e) { if (e.status === 400 && /Only one of user or group/.test(e.body.message)) { splitIntoTwoRequests(); } else { throw e; } }

Prevention

When it happens

Trigger: POST /runtime/tasks/{taskId}/identitylinks with a body containing both fields, e.g. {"type":"candidate","user":"kermit","group":"management"}.

Common situations: UIs that keep the previous selection populated when switching between user/group modes; bulk-merge code that copies all form fields into the payload.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/2aeb2761d12ba007. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskIdentityLinkCollectionResource.java:75

    @ApiOperation(value = "Create an identity link on a task", tags = { "Task Identity Links" }, nickname = "createTaskInstanceIdentityLinks",
            notes = "It is possible to add either a user or a group.", code = 201)
    @ApiResponses(value = {
            @ApiResponse(code = 201, message = "Indicates the task was found and the identity link was created."),
            @ApiResponse(code = 404, message = "Indicates the requested task was not found or the task does not have the requested identityLink. The status contains additional information about this error.")
    })
    @PostMapping(value = "/runtime/tasks/{taskId}/identitylinks", produces = "application/json")
    @ResponseStatus(HttpStatus.CREATED)
    public RestIdentityLink createIdentityLink(@ApiParam(name = "taskId") @PathVariable("taskId") String taskId, @RequestBody RestIdentityLink identityLink) {

        Task task = getTaskFromRequestWithoutAccessCheck(taskId);

        if (identityLink.getGroup() == null && identityLink.getUser() == null) {
            throw new FlowableIllegalArgumentException("A group or a user is required to create an identity link.");
        }

        if (identityLink.getGroup() != null && identityLink.getUser() != null) {
            throw new FlowableIllegalArgumentException("Only one of user or group can be used to create an identity link.");
        }

        if (identityLink.getType() == null) {
            throw new FlowableIllegalArgumentException("The identity link type is required.");
        }

        if (restApiInterceptor != null) {
            restApiInterceptor.createTaskIdentityLink(task, identityLink);
        }

        if (identityLink.getGroup() != null) {
            taskService.addGroupIdentityLink(task.getId(), identityLink.getGroup(), identityLink.getType());
        } else {
            taskService.addUserIdentityLink(task.getId(), identityLink.getUser(), identityLink.getType());
        }

        return restResponseFactory.createRestIdentityLink(identityLink.getType(), identityLink.getUser(), identityLink.getGroup(), task.getId(), null, null);
    }

View on GitHub (pinned to d6d39ce1c6)