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
- Add "type" to the body with a valid identity link type, e.g. {"type":"participant","user":"kermit"}.
- Fix DTO/JSON key mapping so the type value actually serializes under "type".
- 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
- Default the type in your client wrapper (e.g. to 'participant') when unset.
- Keep a whitelist of valid identity link types.
- Ensure the DTO field serializes under the key "type".
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
- Only one value of user or group is supported.
- User or group are required.
- A group or a user is required to create an identity link.
- Identity link family should be 'users' or 'groups'.
- Identity link family should be 'users' or 'groups'.
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)