flowable/flowable-engine · error · FlowableIllegalArgumentException
rootScopeIds is null or empty
Error message
rootScopeIds is null or empty
What it means
ProcessInstanceQueryImpl.processInstanceRootScopeIds(Set<String>) filters process instances by their root scope IDs. Flowable throws FlowableIllegalArgumentException for a null or empty set because an empty ID set cannot select any instances and would produce broken SQL (empty IN clause). The library fails fast at query-construction time.
Solutions
- Only call processInstanceRootScopeIds when the set is non-empty; skip the filter otherwise
- Populate the set with valid root scope IDs retrieved from the instances you intend to filter on
- Fix the upstream lookup that produces an empty ID set
- Catch FlowableIllegalArgumentException and return an empty result intentionally if an empty set genuinely means 'nothing to query'
Example fix
// before
query.processInstanceRootScopeIds(rootScopeIds);
// after
if (rootScopeIds != null && !rootScopeIds.isEmpty()) {
query.processInstanceRootScopeIds(rootScopeIds);
} else {
// no roots to filter on; return empty result or skip filter
} Defensive patterns
Strategy: validation
Validate before calling
if (rootScopeIds == null || rootScopeIds.isEmpty()) {
throw new IllegalArgumentException("At least one root scope id is required");
} Type guard
boolean hasRootScopeIds = rootScopeIds != null && !rootScopeIds.isEmpty();
Try / catch
try {
query.processInstanceRootScopeIds(rootScopeIds);
} catch (FlowableIllegalArgumentException e) {
// return empty result or omit the filter
} Prevention
- Guard all Set-based ID filters before applying them
- Verify upstream ID collection queries actually returned rows
- Handle the 'no roots found' case as business logic, not as an empty filter
When it happens
Trigger: Calling processInstanceRootScopeIds(null) or with an empty set, typically when root scope IDs were collected dynamically (e.g., from parent instances or case roots) and none were found.
Common situations: Batch jobs computing root scope IDs from another query that returned no rows; multi-instance/standalone-deployment setups where root scope tracking isn't populated; copy-paste from processInstanceCallbackIds with wrong variable populated.
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
- parentScopeIds is null or empty
- callbackIds is null or empty
- Involved groups are empty
- variableNames are null or empty
- at least one of userId or groups must be provided
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/b393e6fd5dd7728d.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/ProcessInstanceQueryImpl.java:718
this.nameLikeIgnoreCase = nameLikeIgnoreCase.toLowerCase();
}
return this;
}
@Override
public ProcessInstanceQuery processInstanceRootScopeId(String rootId) {
if (inOrStatement) {
this.currentOrQueryObject.rootScopeId = rootId;
} else {
this.rootScopeId = rootId;
}
return this;
}
@Override
public ProcessInstanceQuery processInstanceRootScopeIds(Set<String> rootScopeIds) {
if (rootScopeIds == null || rootScopeIds.isEmpty()) {
throw new FlowableIllegalArgumentException("rootScopeIds is null or empty");
}
if (inOrStatement) {
this.currentOrQueryObject.rootScopeIds = rootScopeIds;
} else {
this.rootScopeIds = rootScopeIds;
}
return this;
}
@Override
public ProcessInstanceQuery processInstanceParentScopeId(String parentId) {
if (inOrStatement) {
this.currentOrQueryObject.parentScopeId = parentId;
} else {
this.parentScopeId = parentId;
}
return this;
}View on GitHub (pinned to d6d39ce1c6)