flowable/flowable-engine · error · ActivitiIllegalArgumentException

Invalid query usage: cannot set both candidateGroup and…

Error message

Invalid query usage: cannot set both candidateGroup and candidateGroupIn

What it means

taskCandidateGroup(String candidateGroup) throws this error when candidateGroups (the list set via taskCandidateGroupIn) is already populated. A single candidate group and a candidate-group list are mutually exclusive filters; both would produce conflicting identity-link conditions. Remove one of the two calls.

Solutions

  1. Use taskCandidateGroupIn(list) exclusively, with the single group wrapped in a one-element list
  2. Rebuild the query instead of reusing a partially configured TaskQueryImpl
  3. Centralize candidate-group filtering in one helper that picks either single or list mode

Example fix

// before
query.taskCandidateGroupIn(groupList);
query.taskCandidateGroup("hr"); // throws
// after
List<String> groups = new ArrayList<>(groupList);
groups.add("hr");
query.taskCandidateGroupIn(groups);
Defensive patterns

Strategy: validation

Validate before calling

if (singleGroup != null && groupList != null) {
    throw new IllegalStateException("Use either taskCandidateGroup or taskCandidateGroupIn, not both");
}

Try / catch

try {
    query.taskCandidateGroup(singleGroup);
} catch (ActivitiIllegalArgumentException e) {
    log.warn("Candidate group filters conflict: {}", e.getMessage());
    query = taskService.createTaskQuery().taskCandidateGroupIn(groupList);
}

Prevention

When it happens

Trigger: Calling taskQuery.taskCandidateGroup("hr") after taskQuery.taskCandidateGroupIn(list) on the same query object (or same OR block). The check compares against the candidateGroups field at TaskQueryImpl.java:518.

Common situations: Composing queries from layered services that each add their own group filter; migrating from a single group to a group list while keeping the old call; generic search forms that support both modes without resetting the query.

Related errors


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

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/TaskQueryImpl.java:518

        if (involvedUser == null) {
            throw new ActivitiIllegalArgumentException("Involved user is null");
        }
        if (orActive) {
            currentOrQueryObject.involvedUser = involvedUser;
        } else {
            this.involvedUser = involvedUser;
        }
        return this;
    }

    @Override
    public TaskQueryImpl taskCandidateGroup(String candidateGroup) {
        if (candidateGroup == null) {
            throw new ActivitiIllegalArgumentException("Candidate group is null");
        }

        if (candidateGroups != null) {
            throw new ActivitiIllegalArgumentException("Invalid query usage: cannot set both candidateGroup and candidateGroupIn");
        }

        if (orActive) {
            currentOrQueryObject.candidateGroup = candidateGroup;
        } else {
            this.candidateGroup = candidateGroup;
        }
        return this;
    }

    @Override
    public TaskQuery taskCandidateOrAssigned(String userIdForCandidateAndAssignee) {
        if (candidateGroup != null) {
            throw new ActivitiIllegalArgumentException("Invalid query usage: cannot set candidateGroup");
        }
        if (candidateUser != null) {
            throw new ActivitiIllegalArgumentException("Invalid query usage: cannot set both candidateGroup and candidateUser");
        }

View on GitHub (pinned to d6d39ce1c6)