flowable/flowable-engine · error · ActivitiIllegalArgumentException

type is required when adding a new task identity link

Error message

type is required when adding a new task identity link

What it means

AddIdentityLinkCmd adds an identity link (user/group association) to a task. Before executing, validateParams checks that the identity link 'type' (e.g. assignee, candidate, owner) is non-null. Flowable throws ActivitiIllegalArgumentException because an identity link without a type is meaningless and cannot be persisted.

Solutions

  1. Pass a valid IdentityLinkType constant (ASSIGNEE, OWNER, CANDIDATE, PARTICIPANT) as the type argument
  2. Check the type variable for null before calling addIdentityLink
  3. If the type comes from external input, default to IdentityLinkType.CANDIDATE or reject the request early

Example fix

// before
taskService.addUserIdentityLink(taskId, userId, linkType); // linkType is null
// after
String type = linkType != null ? linkType : IdentityLinkType.CANDIDATE;
taskService.addUserIdentityLink(taskId, userId, type);
Defensive patterns

Strategy: validation

Validate before calling

if (taskId == null || linkType == null) {
    throw new IllegalArgumentException("taskId and linkType are required");
}

Try / catch

try {
    taskService.addUserIdentityLink(taskId, userId, linkType);
} catch (ActivitiIllegalArgumentException e) {
    if (e.getMessage().contains("type is required")) {
        taskService.addUserIdentityLink(taskId, userId, IdentityLinkType.CANDIDATE);
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling taskService.addUserIdentityLink(taskId, userId, null), taskService.addGroupIdentityLink with a null type, or constructing AddIdentityLinkCmd directly with type == null.

Common situations: Passing a variable holding the link type that was never initialized; reading the type from config/JSON where the key is missing; confusion between identityId and identityType parameters due to similar names.

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

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/cmd/AddIdentityLinkCmd.java:51

    protected String identityType;

    public AddIdentityLinkCmd(String taskId, String identityId, int identityIdType, String identityType) {
        super(taskId);
        validateParams(taskId, identityId, identityIdType, identityType);
        this.taskId = taskId;
        this.identityId = identityId;
        this.identityIdType = identityIdType;
        this.identityType = identityType;
    }

    protected void validateParams(String taskId, String identityId, int identityIdType, String identityType) {
        if (taskId == null) {
            throw new ActivitiIllegalArgumentException("taskId is null");
        }

        if (identityType == null) {
            throw new ActivitiIllegalArgumentException("type is required when adding a new task identity link");
        }

        if (identityId == null && (identityIdType == IDENTITY_GROUP ||
                (!IdentityLinkType.ASSIGNEE.equals(identityType) && !IdentityLinkType.OWNER.equals(identityType)))) {

            throw new ActivitiIllegalArgumentException("identityId is null");
        }

        if (identityIdType != IDENTITY_USER && identityIdType != IDENTITY_GROUP) {
            throw new ActivitiIllegalArgumentException("identityIdType allowed values are 1 and 2");
        }
    }

    @Override
    protected Void execute(CommandContext commandContext, TaskEntity task) {

        boolean assignedToNoOne = false;
        if (IdentityLinkType.ASSIGNEE.equals(identityType)) {

View on GitHub (pinned to d6d39ce1c6)