flowable/flowable-engine · error · ActivitiIllegalArgumentException

userId and groupId cannot both be null

Error message

userId and groupId cannot both be null

What it means

AddIdentityLinkForProcessInstanceCmd requires that at least one of userId or groupId is provided; an identity link must reference a user or a group. When both are null, validateParams throws ActivitiIllegalArgumentException.

Solutions

  1. Provide a userId or a groupId (one of them must be non-null)
  2. Validate inputs before the call and reject empty user/group pairs
  3. Check argument order: signature is (processInstanceId, userId, groupId, type)

Example fix

// before
runtimeService.addUserIdentityLinkForProcessInstance(pid, userId, groupId, type); // both null
// after
if (userId == null && groupId == null) {
    throw new IllegalArgumentException("userId or groupId required");
}
runtimeService.addUserIdentityLinkForProcessInstance(pid, userId, groupId, type);
Defensive patterns

Strategy: validation

Validate before calling

if (userId == null && groupId == null) {
    throw new IllegalArgumentException("userId or groupId is required");
}

Try / catch

try {
    runtimeService.addUserIdentityLinkForProcessInstance(pid, userId, groupId, type);
} catch (ActivitiIllegalArgumentException e) {
    if (e.getMessage().contains("both be null")) {
        // reject the request or supply a default identity
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling runtimeService.addUserIdentityLinkForProcessInstance(pid, null, type) with both identifiers absent, or constructing the command with userId == null and groupId == null.

Common situations: Empty form submissions where neither user nor group was filled in; upstream user-directory lookup returned null for both; swapped arguments placing the type where userId should be.

Related errors


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

Appendix: source

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

        validateParams(processInstanceId, userId, groupId, type);
        this.processInstanceId = processInstanceId;
        this.userId = userId;
        this.groupId = groupId;
        this.type = type;
    }

    protected void validateParams(String processInstanceId, String userId, String groupId, String type) {

        if (processInstanceId == null) {
            throw new ActivitiIllegalArgumentException("processInstanceId is null");
        }

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

        if (userId == null && groupId == null) {
            throw new ActivitiIllegalArgumentException("userId and groupId cannot both be null");
        }

    }

    @Override
    public Void execute(CommandContext commandContext) {

        ExecutionEntity processInstance = commandContext.getExecutionEntityManager().findExecutionById(processInstanceId);

        if (processInstance == null) {
            throw new ActivitiObjectNotFoundException("Cannot find process instance with id " + processInstanceId, ExecutionEntity.class);
        }

        processInstance.addIdentityLink(userId, groupId, type);

        commandContext.getHistoryManager().createProcessInstanceIdentityLinkComment(processInstanceId, userId, groupId, type, true);

        return null;

View on GitHub (pinned to d6d39ce1c6)