flowable/flowable-engine · error · ActivitiIllegalArgumentException
Process instance id list is empty
Error message
Process instance id list is empty
What it means
HistoricTaskInstanceQueryImpl.processInstanceIdIn() throws ActivitiIllegalArgumentException when the supplied process instance id list is non-null but empty. The library requires at least one id because an SQL IN clause with no values would be invalid or return nothing. Pass a non-empty list of process instance ids.
Solutions
- Ensure the list passed to processInstanceIdIn contains at least one process instance id before building the query.
- If the id list may be empty, skip the query or use a different filter entirely instead of calling processInstanceIdIn.
- Guard the call with a size check: if (ids != null && !ids.isEmpty()) query.processInstanceIdIn(ids);
Example fix
// before
List<String> ids = collectIds(); // may be empty
query.processInstanceIdIn(ids);
// after
List<String> ids = collectIds();
if (!ids.isEmpty()) {
query.processInstanceIdIn(ids);
} else {
return Collections.emptyList(); // no candidates, skip query
} Defensive patterns
Strategy: validation
Validate before calling
if (processInstanceIds == null || processInstanceIds.isEmpty()) { throw new IllegalArgumentException("processInstanceIds must contain at least one id"); }
for (String id : processInstanceIds) { if (id == null) { throw new IllegalArgumentException("processInstanceIds must not contain nulls"); } } Type guard
static boolean isUsableIdList(List<String> ids) { return ids != null && !ids.isEmpty() && ids.stream().allMatch(Objects::nonNull); } Try / catch
try {
query.processInstanceIdIn(ids);
} catch (org.activiti.engine.ActivitiIllegalArgumentException e) {
log.warn("Invalid processInstanceIdIn argument: {}", e.getMessage());
// fall back to unfiltered query or return empty result
} Prevention
- Never call *In(...) query methods with collections that may be empty; gate them behind size checks.
- Normalize collections (remove nulls, require non-empty) in one shared query-builder helper.
- Write unit tests covering empty/null lists for every query filter you use.
When it happens
Trigger: Calling historicTaskInstanceQuery.processInstanceIdIn(new ArrayList<>()) (or any empty List<String>) on the query object.
Common situations: Building the id list dynamically from an upstream search that matched nothing; passing a collection that was filtered to empty; wiring a default empty collection into query construction.
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
- None of the given process categories can be null
- None of the given process instance ids can be null
- Process category list is empty
- Process category list is null
- Process definition category is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/e4fd293e20a1868d.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/HistoricTaskInstanceQueryImpl.java:165
}
@Override
public HistoricTaskInstanceQueryImpl processInstanceId(String processInstanceId) {
if (inOrStatement) {
this.currentOrQueryObject.processInstanceId = processInstanceId;
} else {
this.processInstanceId = processInstanceId;
}
return this;
}
@Override
public HistoricTaskInstanceQueryImpl processInstanceIdIn(List<String> processInstanceIds) {
if (processInstanceIds == null) {
throw new ActivitiIllegalArgumentException("Process instance id list is null");
}
if (processInstanceIds.isEmpty()) {
throw new ActivitiIllegalArgumentException("Process instance id list is empty");
}
for (String processInstanceId : processInstanceIds) {
if (processInstanceId == null) {
throw new ActivitiIllegalArgumentException("None of the given process instance ids can be null");
}
}
if (inOrStatement) {
this.currentOrQueryObject.processInstanceIds = processInstanceIds;
} else {
this.processInstanceIds = processInstanceIds;
}
return this;
}
@Override
public HistoricTaskInstanceQueryImpl processInstanceBusinessKey(String processInstanceBusinessKey) {
if (inOrStatement) {View on GitHub (pinned to d6d39ce1c6)