flowable/flowable-engine · error · FlowableIllegalArgumentException

Invalid query usage: cannot set candidateGroup

Error message

Invalid query usage: cannot set candidateGroup

What it means

TaskQueryImpl.taskCandidateOrAssigned() throws this when candidateGroup was already set on the query. candidateOrAssigned filters by candidate user and/or assignee, which is incompatible with a candidate-group filter on the same query. The conflict is detected eagerly at build time.

Solutions

  1. Remove one of the conflicting setters; keep either candidateGroup or candidateOrAssigned.
  2. Create a new query instance per request to avoid leftover state.
  3. If both group and user filtering are needed, run two queries or use or() semantics deliberately with only compatible criteria.
  4. Restructure the builder so the group filter branch excludes the candidateOrAssigned branch.

Example fix

// before
query.taskCandidateGroup("management");
query.taskCandidateOrAssigned(userId);
// after
TaskQuery query = taskService.createTaskQuery();
if (useGroupFilter) {
    query.taskCandidateGroup("management");
} else {
    query.taskCandidateOrAssigned(userId);
}
Defensive patterns

Strategy: validation

Validate before calling

if (useGroupFilter) {
    query.taskCandidateGroup(group);
} else {
    query.taskCandidateOrAssigned(userId);
}

Try / catch

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

Prevention

When it happens

Trigger: Calling taskQuery.taskCandidateOrAssigned(userId) after taskCandidateGroup("g"), including state left from a reused query object or an or() branch where candidateGroup was set first.

Common situations: Combining query-building code paths for group-based and user-based task assignment; reusing a TaskQuery across iterations; conditional logic that sets candidateGroup for some inputs then falls through to candidateOrAssigned.

Related errors


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

Appendix: source

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

            throw new FlowableIllegalArgumentException("Candidate group is null");
        }

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

View on GitHub (pinned to d6d39ce1c6)