flowable/flowable-engine · error · FlowableIllegalArgumentException

The identity link type is required.

Error message

The identity link type is required.

What it means

Every identity link must have a type (e.g. 'participant', 'candidate', 'starter', or a custom type). If the type field is null in the request body, createIdentityLink throws FlowableIllegalArgumentException('The identity link type is required.') since Flowable cannot categorize the link.

Solutions

  1. Add "type" to the body with a valid identity link type, e.g. {"type":"participant","user":"kermit"}.
  2. Fix DTO/JSON key mapping so the type value actually serializes under "type".
  3. Consult the identity link types (GET /identity/link types or docs) and pick the right one for your use case.

Example fix

// before
{"user":"kermit"}
// after
{"type":"participant","user":"kermit"}
Defensive patterns

Strategy: validation

Validate before calling

if (link.getType() == null || link.getType().isEmpty()) {
    throw new IllegalArgumentException("Identity link 'type' is required (e.g. participant)");
}

Try / catch

try {
    restClient.createIdentityLink(instanceId, link);
} catch (HttpClientErrorException.BadRequest e) {
    if (e.getResponseBodyAsString().contains("identity link type is required")) {
        // set type and retry
    }
}

Prevention

When it happens

Trigger: POST /runtime/process-instances/{id}/identitylinks with {"user":"kermit"} — body lacks "type". Thrown at ProcessInstanceIdentityLinkCollectionResource.java:84.

Common situations: Assuming the API defaults the type to 'participant' (it does not); DTO field name mismatch ("linkType" vs "type"); JSON serializers omitting the field when unset.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/ProcessInstanceIdentityLinkCollectionResource.java:84

            @ApiResponse(code = 400, message = "Indicates the requested body did not contain a userId or a type."),
            @ApiResponse(code = 404, message = "Indicates the requested process instance was not found.")
    })
    @PostMapping(value = "/runtime/process-instances/{processInstanceId}/identitylinks", produces = "application/json")
    @ResponseStatus(HttpStatus.CREATED)
    public RestIdentityLink createIdentityLink(@ApiParam(name = "processInstanceId") @PathVariable String processInstanceId, @RequestBody RestIdentityLink identityLink) {

        ProcessInstance processInstance = getProcessInstanceFromRequestWithoutAccessCheck(processInstanceId);

        if (identityLink.getGroup() == null && identityLink.getUser() == null) {
            throw new FlowableIllegalArgumentException("User or group are required.");
        }
        
        if (StringUtils.isEmpty(identityLink.getGroup()) && StringUtils.isEmpty(identityLink.getUser())) {
            throw new FlowableIllegalArgumentException("Only one value of user or group is supported.");
        }

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

        if (restApiInterceptor != null) {
            restApiInterceptor.createProcessInstanceIdentityLink(processInstance, identityLink);
        }

        if (StringUtils.isNotEmpty(identityLink.getGroup())) {
            runtimeService.addGroupIdentityLink(processInstance.getId(), identityLink.getGroup(), identityLink.getType());
            
        } else {
            runtimeService.addUserIdentityLink(processInstance.getId(), identityLink.getUser(), identityLink.getType());
        }

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

View on GitHub (pinned to d6d39ce1c6)