flowable/flowable-engine · error · ActivitiIllegalArgumentException

Invalid query usage: cannot set both candidateGroup and…

Error message

Invalid query usage: cannot set both candidateGroup and candidateUser

What it means

taskCandidateOrAssigned(String userIdForCandidateAndAssignee) throws this error when candidateUser has already been set via taskCandidateUser(...). taskCandidateOrAssigned already includes candidate-user semantics, so combining it with taskCandidateUser would duplicate/conflict the identity-link conditions. Use one or the other.

Solutions

  1. Remove the taskCandidateUser call and rely on taskCandidateOrAssigned alone
  2. If both semantics are truly needed, issue separate queries and union the results in application code
  3. Add a builder/validation layer that asserts only one candidate-filter mode is configured

Example fix

// before
query.taskCandidateUser("kermit");
query.taskCandidateOrAssigned("kermit"); // throws
// after
query.taskCandidateOrAssigned("kermit");
Defensive patterns

Strategy: validation

Validate before calling

if (candidateUser != null && candidateOrAssignedUser != null) {
    throw new IllegalStateException("taskCandidateOrAssigned already covers candidate-user semantics");
}

Try / catch

try {
    query.taskCandidateOrAssigned(userId);
} catch (ActivitiIllegalArgumentException e) {
    log.warn("candidateUser already set: {}", e.getMessage());
    query = taskService.createTaskQuery().taskCandidateUser(candidateUser);
}

Prevention

When it happens

Trigger: Calling taskQuery.taskCandidateOrAssigned(userId) after taskQuery.taskCandidateUser(someUser) on the same query (or within the same OR block) - checked at TaskQueryImpl.java:535.

Common situations: Query composition layers that add a candidate-user filter while a newer code path switched to candidate-or-assigned; refactoring a task list to show claimed+unclaimed tasks but leaving the old candidateUser call; copy-pasted OR query blocks.

Related errors


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

Appendix: source

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

        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");
        }

        if (orActive) {
            currentOrQueryObject.bothCandidateAndAssigned = true;
            currentOrQueryObject.userIdForCandidateAndAssignee = userIdForCandidateAndAssignee;
        } else {
            this.bothCandidateAndAssigned = true;
            this.userIdForCandidateAndAssignee = userIdForCandidateAndAssignee;
        }

        return this;
    }

    @Override
    public TaskQuery taskCandidateGroupIn(List<String> candidateGroups) {
        if (candidateGroups == null) {
            throw new ActivitiIllegalArgumentException("Candidate group list is null");
        }

View on GitHub (pinned to d6d39ce1c6)