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

A HistoricIdentityLinkEntity represents one assignment/identity link on a historic task and must be either user-based or group-based, never both. setUserId rejects assigning a userId when a groupId is already present, since the persisted row would become ambiguous.

Solutions

  1. Create a separate entity for the user assignment instead of reusing one that already holds a groupId.
  2. Set groupId to null before calling setUserId if the link really should switch to user-based.
  3. Distinguish candidate-group links from assignee links in your mapping code: one IdentityLink = one principal type.

Example fix

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

// after
HistoricIdentityLinkEntity groupLink = ...; groupLink.setGroupId("management");
HistoricIdentityLinkEntity userLink = ...; userLink.setUserId("kermit");
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

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

Try / catch

try {
    link.setUserId(userId);
} catch (ActivitiException e) {
    link = createNewIdentityLink(); // start a fresh link for the user
    link.setUserId(userId);
}

Prevention

When it happens

Trigger: Calling setUserId (directly or via entity manipulation / custom history mapping) on a HistoricIdentityLinkEntity whose groupId field is already non-null and passing a non-null userId.

Common situations: Custom code copying IdentityLink data between entities without clearing the opposite field; history-level configuration or event listeners that mutate identity link entities; data import/migration scripts that reuse an entity for both group and user assignments.

Related errors


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

Appendix: source

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

    }

    @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)