flowable/flowable-engine · error · FlowableIllegalArgumentException

Set of process instance ids is empty

Error message

Set of process instance ids is empty

What it means

Flowable's HistoricProcessInstanceQuery.processInstanceIds(Set<String>) rejects empty sets. An empty id set would produce an impossible or unbounded SQL IN clause, so the API throws FlowableIllegalArgumentException at query-build time. Callers must supply at least one process instance id.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/HistoricProcessInstanceQueryImpl.java:164

    }

    @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 FlowableIllegalArgumentException("Set of process instance ids is null");
        }
        if (processInstanceIds.isEmpty()) {
            throw new FlowableIllegalArgumentException("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. Populate the set with at least one id before calling processInstanceIds
  2. Guard the call with !ids.isEmpty() and skip/alter the query when empty
  3. Decide on explicit behavior for the empty case: return no results early instead of executing the query
  4. Use a different query criterion entirely when no ids are known

Example fix

// before
query.processInstanceIds(ids); // throws when ids.isEmpty()
// after
if (ids != null && !ids.isEmpty()) {
    query.processInstanceIds(ids);
} else {
    return Collections.emptyList();
}
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

boolean hasElements(Set<String> s) {
    return s != null && !s.isEmpty();
}

Try / catch

try {
    query.processInstanceIds(ids);
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().contains("empty")) {
        return Collections.emptyList();
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling processInstanceIds(ids) where ids is a non-null but empty Set — e.g. new HashSet<>() passed directly, or a filtered collection that ended up with zero elements.

Common situations: Filtering results upstream removed all entries before the query was built; initializing a set but never populating it; paging logic that produced an empty batch of ids.

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/bb42cd450f873326. Report an issue: GitHub.