flowable/flowable-engine · error · FlowableIllegalArgumentException

IdentityId is required.

Error message

IdentityId is required.

What it means

Flowable REST throws FlowableIllegalArgumentException when validating identity link arguments on a process instance. The identityId path segment (user or group id) was null/absent when resolving the identity link URL. The REST API requires family, identityId, and type segments to look up or delete an identity link.

Solutions

  1. Ensure the identityId path segment is non-empty in the request URL.
  2. Validate the user/group id variable before building the URL client-side.
  3. Use URL templates/encoders instead of string concatenation to avoid empty segments.

Example fix

// before
String url = "/runtime/process-instances/" + pid + "/identitylinks/users/" + userId + "/participant";
// after
if (userId == null || userId.isEmpty()) throw new IllegalArgumentException("userId required");
String url = "/runtime/process-instances/" + pid + "/identitylinks/users/" + URLEncoder.encode(userId, UTF_8) + "/participant";
Defensive patterns

Strategy: validation

Validate before calling

if (!userId) throw new Error('userId required before calling identity link endpoint');

Type guard

const hasIdentityId = (s) => typeof s === 'string' && s.length > 0;

Prevention

When it happens

Trigger: DELETE or GET to /runtime/process-instances/{id}/identitylinks/users/{identityId}/{type} or /groups/{identityId}/{type} with an empty or missing {identityId} path segment, e.g. .../identitylinks/users//participant.

Common situations: URL built by string concatenation with an uninitialized user/group variable; client template placeholders ({userId}) not filled in; trailing path manipulation accidentally removing the segment.

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/d5e6d48ce90fb68a. Report an issue: GitHub.

Appendix: source

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

        if (restApiInterceptor != null) {
            restApiInterceptor.deleteProcessInstanceIdentityLink(processInstance, link);
        }

        if (RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_GROUPS.equals(family)) {
            runtimeService.deleteGroupIdentityLink(processInstance.getId(), identityId, type);
            
        } else {
            runtimeService.deleteUserIdentityLink(processInstance.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 identityId, String family, String type, String processInstanceId) {
        // Perhaps it would be better to offer getting a single identity link
        // from the API
        List<IdentityLink> allLinks = runtimeService.getIdentityLinksForProcessInstance(processInstanceId);
        for (IdentityLink link : allLinks) {
            if (RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_USERS.equals(family) && identityId.equals(link.getUserId()) && link.getType().equals(type)) {
                return link;
            
            } else if (RestUrls.SEGMENT_IDENTITYLINKS_FAMILY_GROUPS.equals(family) && identityId.equals(link.getGroupId()) && link.getType().equals(type)) {
                return link;
            }
        }

View on GitHub (pinned to d6d39ce1c6)