flowable/flowable-engine · warning · FlowableIllegalArgumentException

Identity link family should be 'users' or 'groups'.

Error message

Identity link family should be 'users' or 'groups'.

What it means

Shared argument validator for single identity-link operations (GET/DELETE on /runtime/tasks/{taskId}/identitylinks/{family}/{identityId}/{type}). It rejects a family other than 'users'/'groups', a null identityId, or a null type with FlowableIllegalArgumentException.

Solutions

  1. Build the URL with all three segments, e.g. /identitylinks/users/kermit/candidate
  2. Use only 'users' or 'groups' as the family segment
  3. URL-encode the identityId and type to avoid empty segments

Example fix

// before
GET /runtime/tasks/123/identitylinks/users/kermit
// after
GET /runtime/tasks/123/identitylinks/users/kermit/candidate
Defensive patterns

Strategy: validation

Validate before calling

const FAMILIES = ['users', 'groups'];
if (!FAMILIES.includes(family) || !identityId || !type) {
  throw new Error('family must be users|groups; identityId and type are required');
}

Try / catch

try { ... } catch (e) { if (e.status === 400 && /Identity link family|IdentityId is required|Type is required/.test(e.body.message)) { reportInvalidUrlSegments(); } else { throw e; } }

Prevention

When it happens

Trigger: GET or DELETE /runtime/tasks/{taskId}/identitylinks/{family}/{identityId}/{type} where family is not 'users'/'groups', identityId is empty, or type is missing/empty.

Common situations: URL-encoding dropping empty path variables; constructed URLs missing the type segment; family pluralization errors as in 3708.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

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

        validateIdentityLinkArguments(family, identityId, type);

        // Check if identitylink to delete exists
        IdentityLink link = getIdentityLink(family, identityId, type, task.getId());

        if (restApiInterceptor != null) {
            restApiInterceptor.deleteTaskIdentityLink(task, link);
        }

        if (RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_USERS.equals(family)) {
            taskService.deleteUserIdentityLink(task.getId(), identityId, type);
        } else {
            taskService.deleteGroupIdentityLink(task.getId(), identityId, type);
        }
    }

    protected void validateIdentityLinkArguments(String family, String identityId, String type) {
        if (family == null || (!RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_GROUPS.equals(family) && !RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_USERS.equals(family))) {
            throw new FlowableIllegalArgumentException("Identity link family should be 'users' or 'groups'.");
        }
        if (identityId == null) {
            throw new FlowableIllegalArgumentException("IdentityId is required.");
        }
        if (type == null) {
            throw new FlowableIllegalArgumentException("Type is required.");
        }
    }

    protected IdentityLink getIdentityLink(String family, String identityId, String type, String taskId) {
        boolean isUser = family.equals(RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_USERS);

        // Perhaps it would be better to offer getting a single identitylink
        // from the API
        List<IdentityLink> allLinks = taskService.getIdentityLinksForTask(taskId);
        for (IdentityLink link : allLinks) {
            boolean rightIdentity = false;
            if (isUser) {

View on GitHub (pinned to d6d39ce1c6)