flowable/flowable-engine · error · FlowableIllegalArgumentException

userId and groupId cannot both be null

Error message

userId and groupId cannot both be null

What it means

AddIdentityLinkForCaseInstanceCmd.validateParams throws FlowableIllegalArgumentException when both userId and groupId are null. An identity link must point to at least one principal (user or group); creating one referencing neither would be meaningless, so the command rejects it up front.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/AddIdentityLinkForCaseInstanceCmd.java:61

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

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

        if (caseInstanceId == null) {
            throw new FlowableIllegalArgumentException("caseInstanceId is null");
        }

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

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

    }

    @Override
    public Void execute(CommandContext commandContext) {
        CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
        CaseInstanceEntityManager caseInstanceEntityManager = cmmnEngineConfiguration.getCaseInstanceEntityManager();
        CaseInstanceEntity caseInstance = caseInstanceEntityManager.findById(caseInstanceId);

        if (caseInstance == null) {
            throw new FlowableObjectNotFoundException("Cannot find case instance with id " + caseInstanceId, CaseInstanceEntity.class);
        }

        IdentityLinkUtil.createCaseInstanceIdentityLink(caseInstance, userId, groupId, type, cmmnEngineConfiguration);
        
        return null;

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Provide either a userId or a groupId (at least one non-null) when adding the identity link
  2. Validate user/group presence in caller code before invoking the API
  3. If the intent was a link to neither, use a different mechanism (e.g. case metadata) instead of an identity link

Example fix

// before
cmmnRuntimeService.addIdentityLinkForCaseInstance(caseInstanceId, null, null, "participant");
// after
cmmnRuntimeService.addIdentityLinkForCaseInstance(caseInstanceId, "kermit", null, "participant");
Defensive patterns

Strategy: validation

Validate before calling

if (userId == null && groupId == null) throw new IllegalArgumentException("Either userId or groupId must be provided");

Type guard

boolean hasPrincipal(String userId, String groupId) { return userId != null || groupId != null; }

Try / catch

try {
    cmmnRuntimeService.addIdentityLinkForCaseInstance(caseId, userId, groupId, type);
} catch (FlowableIllegalArgumentException e) {
    log.warn("Cannot add identity link: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Calling addIdentityLinkForCaseInstance (or constructing the command) with type set but both userId and groupId null/omitted — e.g. a REST call supplying only the type, or variables holding the assignee/group both resolving to null.

Common situations: Optional assignee not filled in by the caller; both user and group fields left blank in a UI-driven API request; code intended to add a group link but the group variable was never set.

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