flowable/flowable-engine · error · FlowableIllegalArgumentException

A group or a user is required to create an identity link.

Error message

A group or a user is required to create an identity link.

What it means

Thrown when creating an identity link on a process definition (POST /repository/process-definitions/{processDefinitionId}/identitylinks) when the request body specifies neither a group nor a user. An identity link must associate the definition with at least one of the two.

Solutions

  1. Include either "user":"<userId>" or "group":"<groupId>" in the request body
  2. Validate the body before sending (only one of user/group set, type provided)
  3. If you meant a candidate-starter for a group, set the group field instead of leaving both blank

Example fix

// before
{"type":"candidate"}
// after
{"type":"candidate","group":"sales"}
Defensive patterns

Strategy: validation

Validate before calling

if (body.getGroup() == null && body.getUser() == null) throw new IllegalArgumentException("identity link needs a user or a group");

Try / catch

try { createIdentityLink(defId, link); } catch (FlowableIllegalArgumentException e) { /* prompt user to pick a user or group */ }

Prevention

When it happens

Trigger: POST identity link with a JSON body where both 'user' and 'group' are null/missing, e.g. {"type":"candidate"} only.

Common situations: Clients omitting fields when generalizing user/group link code; templates with unfilled placeholders; payload built dynamically where both variables end up null.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/repository/ProcessDefinitionIdentityLinkCollectionResource.java:75

        return restResponseFactory.createRestIdentityLinks(repositoryService.getIdentityLinksForProcessDefinition(processDefinition.getId()));
    }

    @ApiOperation(value = "Add a candidate starter to a process definition", tags = { "Process Definitions" },
            notes = "It is possible to add either a user or a group.",
            code = 201)
    @ApiResponses(value = {
            @ApiResponse(code = 201, message = "Indicates the process definition was found and the identity link was created."),
            @ApiResponse(code = 400, message = "Indicates the body does not contain the correct information."),
            @ApiResponse(code = 404, message = "Indicates the requested process definition was not found.")
    })
    @PostMapping(value = "/repository/process-definitions/{processDefinitionId}/identitylinks", produces = "application/json")
    @ResponseStatus(HttpStatus.CREATED)
    public RestIdentityLink createIdentityLink(@ApiParam(name = "processDefinitionId") @PathVariable String processDefinitionId, @RequestBody RestIdentityLink identityLink) {

        ProcessDefinition processDefinition = getProcessDefinitionFromRequestWithoutAccessCheck(processDefinitionId);

        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 (restApiInterceptor != null) {
            restApiInterceptor.createProcessDefinitionIdentityLink(processDefinition, identityLink);
        }

        if (identityLink.getGroup() != null) {
            repositoryService.addCandidateStarterGroup(processDefinition.getId(), identityLink.getGroup());
        } else {
            repositoryService.addCandidateStarterUser(processDefinition.getId(), identityLink.getUser());
        }

        // Always candidate for process-definition. User-provided value is
        // ignored

View on GitHub (pinned to d6d39ce1c6)