flowable/flowable-engine · error · FlowableIllegalArgumentException

Type is required.

Error message

Type is required.

What it means

The {type} path variable (the identity link type such as 'candidate') is mandatory when addressing a single identity link, since a user can hold multiple link types on one task. A null type makes the target link ambiguous and triggers FlowableIllegalArgumentException.

Solutions

  1. Include the link type in the URL, e.g. /cmmn-runtime/tasks/123/identitylinks/users/john/candidate
  2. Ensure the client object's type field is populated before constructing the URL
  3. Use the family-level listing endpoint if the type is unknown and needs discovery

Example fix

// before
DELETE /cmmn-runtime/tasks/123/identitylinks/users/john
// after
DELETE /cmmn-runtime/tasks/123/identitylinks/users/john/candidate
Defensive patterns

Strategy: validation

Validate before calling

function canAddressIdentityLink(family, identityId, type) {
  return !!identityId && !!type && ['users','groups'].includes(family);
}

Type guard

function hasType(a) {
  return typeof a.type === 'string' && a.type.length > 0;
}

Try / catch

try {
  await del(url);
} catch (e) {
  if (e.status === 400 && /Type is required/.test(e.body.message)) {
    throw new Error('type path variable missing');
  }
  throw e;
}

Prevention

When it happens

Trigger: GET/DELETE /cmmn-runtime/tasks/{taskId}/identitylinks/{family}/{identityId}/{type} with an empty or missing {type} segment.

Common situations: URL built from a stored identity link object whose 'type' field was never set; templated paths that omit the last segment; confusing this endpoint with the collection POST where type is also required.

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

Appendix: source

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

            restApiInterceptor.deleteTaskIdentityLink(task, link);
        }

        if (CmmnRestUrls.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 || (!CmmnRestUrls.SEGMENT_IDENTITYLINKS_FAMILY_GROUPS.equals(family) && !CmmnRestUrls.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(CmmnRestUrls.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) {
                rightIdentity = identityId.equals(link.getUserId());
            } else {
                rightIdentity = identityId.equals(link.getGroupId());
            }

            if (rightIdentity && link.getType().equals(type)) {

View on GitHub (pinned to d6d39ce1c6)