flowable/flowable-engine · error · FlowableIllegalArgumentException

Invalid query usage: cannot set both candidateGroup and…

Error message

Invalid query usage: cannot set both candidateGroup and candidateUser

What it means

TaskQueryImpl.taskCandidateOrAssigned() throws this when candidateUser was already set. A task query cannot combine a plain candidateUser filter with the candidateOrAssigned (both candidate and assignee) filter, since their identity-link semantics conflict. Flowable validates this at query build time.

Solutions

  1. Use taskCandidateOrAssigned() alone when you want candidate-or-assignee semantics; drop the separate taskCandidateUser() call.
  2. Build a fresh TaskQuery rather than reusing one where candidateUser was previously set.
  3. Refactor shared query-builder helpers so only one candidate-user-style filter is applied.
  4. Check or() branch composition to ensure candidateUser and candidateOrAssigned are not both set.

Example fix

// before
query.taskCandidateUser(userId);
query.taskCandidateOrAssigned(userId);
// after
query.taskCandidateOrAssigned(userId); // covers candidate and assignee
Defensive patterns

Strategy: validation

Validate before calling

query.taskCandidateOrAssigned(userId); // do not also call taskCandidateUser on the same query

Try / catch

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

Prevention

When it happens

Trigger: Calling taskQuery.taskCandidateOrAssigned(userId) after taskCandidateUser(user), or setting candidateUser inside an or() branch before invoking candidateOrAssigned.

Common situations: Incremental query construction where two filters were added; merging code that used candidateUser with code migrated to candidateOrAssigned; reused query objects carrying state.

Related errors


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

Appendix: source

Thrown at modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/TaskQueryImpl.java:643

        if (candidateGroups != null) {
            throw new FlowableIllegalArgumentException("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 FlowableIllegalArgumentException("Invalid query usage: cannot set candidateGroup");
        }
        if (candidateUser != null) {
            throw new FlowableIllegalArgumentException("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(Collection<String> candidateGroups) {
        if (candidateGroups == null) {
            throw new FlowableIllegalArgumentException("Candidate group list is null");
        }

View on GitHub (pinned to d6d39ce1c6)