flowable/flowable-engine · error · ActivitiException

Cannot assign a userId to a task assignment that already…

Error message

Cannot assign a userId to a task assignment that already has a groupId

What it means

Same invariant as the historic variant but for runtime IdentityLinkEntity: a runtime identity link is either user- or group-based. setUserId throws ActivitiException when groupId is already set and a non-null userId is assigned.

Solutions

  1. Add a new IdentityLinkEntity for the assignee instead of reusing the candidate-group link; use taskService.addUserIdentityLink / setAssignee.
  2. Clear groupId first if intentionally converting the link to user-based.
  3. Keep candidate groups and assignees as distinct links — that is how the API and UI expect them.

Example fix

// before
IdentityLinkEntity link = ...; link.setGroupId("management"); link.setUserId("kermit"); // throws

// after
taskService.addCandidateGroup(taskId, "management");
taskService.setAssignee(taskId, "kermit");
Defensive patterns

Strategy: validation

Validate before calling

if (link.getGroupId() != null && userId != null) {
    throw new IllegalArgumentException("cannot assign user to group-based link");
}

Type guard

function isUserLinkAssignable(link) {
  return link.getGroupId() == null;
}

Try / catch

try {
    taskService.addUserIdentityLink(taskId, userId, IdentityLinkType.CANDIDATE);
} catch (ActivitiException e) {
    log.warn("Link conflict on task {}: {}", taskId, e.getMessage());
}

Prevention

When it happens

Trigger: Calling setUserId on a runtime IdentityLinkEntity (e.g., task candidate/assignee links) that already has a groupId set; custom task listeners or assignment code mutating one entity for both a candidate group and an assignee.

Common situations: TaskListener/assignment handler code that adds both candidateGroup and assignee to the same IdentityLinkEntity object; custom REST/API layers building identity links from mixed request payloads; migration tools converting candidate groups to user assignments in place.

Related errors


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

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/persistence/entity/IdentityLinkEntity.java:137

    }

    @Override
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        if (this.groupId != null && userId != null) {
            throw new ActivitiException("Cannot assign a userId to a task assignment that already has a groupId");
        }
        this.userId = userId;
    }

    @Override
    public String getGroupId() {
        return groupId;
    }

    public void setGroupId(String groupId) {
        if (this.userId != null && groupId != null) {
            throw new ActivitiException("Cannot assign a groupId to a task assignment that already has a userId");
        }
        this.groupId = groupId;
    }

    @Override
    public String getTaskId() {

View on GitHub (pinned to d6d39ce1c6)