flowable/flowable-engine · error · ActivitiIllegalArgumentException

Set of process instance ids is empty

Error message

Set of process instance ids is empty

What it means

HistoricProcessInstanceQuery.processInstanceIds(Set<String>) also rejects an empty set with ActivitiIllegalArgumentException, because an empty IN-clause would match nothing and usually indicates a caller bug rather than an intentional filter. You must supply at least one process instance id.

Source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/HistoricProcessInstanceQueryImpl.java:110

    }

    @Override
    public HistoricProcessInstanceQueryImpl processInstanceId(String processInstanceId) {
        if (inOrStatement) {
            this.currentOrQueryObject.processInstanceId = processInstanceId;
        } else {
            this.processInstanceId = processInstanceId;
        }
        return this;
    }

    @Override
    public HistoricProcessInstanceQuery processInstanceIds(Set<String> processInstanceIds) {
        if (processInstanceIds == null) {
            throw new ActivitiIllegalArgumentException("Set of process instance ids is null");
        }
        if (processInstanceIds.isEmpty()) {
            throw new ActivitiIllegalArgumentException("Set of process instance ids is empty");
        }

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

    @Override
    public HistoricProcessInstanceQueryImpl processDefinitionId(String processDefinitionId) {
        if (inOrStatement) {
            this.currentOrQueryObject.processDefinitionId = processDefinitionId;
        } else {
            this.processDefinitionId = processDefinitionId;
        }
        return this;

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Only call processInstanceIds when the set has at least one element; otherwise skip the filter or return an empty result directly.
  2. Validate inputs before the call: if (ids == null || ids.isEmpty()) handle explicitly.
  3. Fix the id-collection step so it either produces real ids or signals 'nothing to do'.
  4. In batch flows, short-circuit the query when the id set is empty.

Example fix

// before
Set<String> ids = findCandidateIds(); // may be empty
query.processInstanceIds(ids);
List<HistoricProcessInstance> r = query.list();
// after
Set<String> ids = findCandidateIds();
List<HistoricProcessInstance> r = ids.isEmpty()
    ? Collections.emptyList()
    : historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list();
Defensive patterns

Strategy: validation

Validate before calling

if (ids == null || ids.isEmpty()) {
    return Collections.emptyList(); // nothing to look up
}
query.processInstanceIds(ids);

Type guard

boolean hasIds(java.util.Collection<?> c) { return c != null && !c.isEmpty(); }

Try / catch

try {
    query.processInstanceIds(ids);
} catch (ActivitiIllegalArgumentException e) {
    if (e.getMessage().contains("is empty")) {
        // treat as empty result or fix id collection step
    }
}

Prevention

When it happens

Trigger: Calling processInstanceIds(new HashSet<>()) or passing a set that was emptied by prior filtering — e.g. ids collected from a search that returned zero matches.

Common situations: Batch job with no work items after filtering; UI passing through an empty selection; upstream query returning no rows and the empty collection being forwarded unchanged.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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