flowable/flowable-engine · error · ActivitiIllegalArgumentException

Invalid query usage: cannot set both taskNameIn and taskName

Error message

Invalid query usage: cannot set both taskNameIn and taskName

What it means

Flowable's HistoricTaskInstanceQuery supports two mutually exclusive ways to filter by task name: an exact name (taskName) and a list of names (taskNameIn). When taskNameIn(List) is called, the query validates that no single-name filter was already set and throws ActivitiIllegalArgumentException if taskName is non-null, because combining them would produce an ambiguous WHERE clause.

Solutions

  1. Choose one filter style: remove the .taskName(...) call before applying taskNameIn, or skip taskNameIn when a single name is known.
  2. Build the query on a fresh HistoricTaskInstanceQuery instance instead of reusing a partially configured one.
  3. In calling code, branch: if the candidate names list size is 1 use taskName(name), otherwise use taskNameIn(names) — never both.

Example fix

// before
query.taskName("review");
query.taskNameIn(names);
// after
if (names.size() == 1) {
    query.taskName(names.get(0));
} else {
    query.taskNameIn(names);
}
Defensive patterns

Strategy: validation

Validate before calling

if (names != null && !names.isEmpty()) {
    if (useExactSingleName) {
        if (names.size() != 1) throw new IllegalStateException("expected exactly one name");
        query.taskName(names.get(0));
    } else {
        query.taskNameIn(names);
    }
}

Type guard

boolean canUseTaskNameIn(HistoricTaskInstanceQueryImpl q) { return q.getTaskName() == null; }

Try / catch

try {
    query.taskNameIn(names);
} catch (org.activiti.engine.ActivitiIllegalArgumentException e) {
    // mutually exclusive with taskName — rebuild query with a single filter
    query = taskService.createHistoricTaskInstanceQuery().taskNameIn(names);
}

Prevention

When it happens

Trigger: Calling historicTaskInstanceQuery.taskNameIn(Arrays.asList("a","b")) after previously calling .taskName("a") on the same query object.

Common situations: Building a query incrementally with optional criteria where a name filter is sometimes applied via taskName and sometimes via taskNameIn depending on user input, causing both to be set when the code path changes.

Related errors


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

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/HistoricTaskInstanceQueryImpl.java:385

        if (inOrStatement) {
            this.currentOrQueryObject.taskName = taskName;
        } else {
            this.taskName = taskName;
        }
        return this;
    }

    @Override
    public HistoricTaskInstanceQuery taskNameIn(List<String> taskNameList) {
        if (taskNameList == null) {
            throw new ActivitiIllegalArgumentException("Task name list is null");
        }
        if (taskNameList.isEmpty()) {
            throw new ActivitiIllegalArgumentException("Task name list is empty");
        }

        if (taskName != null) {
            throw new ActivitiIllegalArgumentException("Invalid query usage: cannot set both taskNameIn and taskName");
        }
        if (taskNameLike != null) {
            throw new ActivitiIllegalArgumentException("Invalid query usage: cannot set both taskNameIn and taskNameLike");
        }
        if (taskNameLikeIgnoreCase != null) {
            throw new ActivitiIllegalArgumentException("Invalid query usage: cannot set both taskNameIn and taskNameLikeIgnoreCase");
        }

        if (inOrStatement) {
            currentOrQueryObject.taskNameList = taskNameList;
        } else {
            this.taskNameList = taskNameList;
        }
        return this;
    }

    @Override
    public HistoricTaskInstanceQuery taskNameInIgnoreCase(List<String> taskNameList) {

View on GitHub (pinned to d6d39ce1c6)