flowable/flowable-engine · error · FlowableIllegalArgumentException
The query is already in an or statement
Error message
The query is already in an or statement
What it means
HistoricPlanItemInstanceQueryImpl.or() throws FlowableIllegalArgumentException if the query is already inside an or block (inOrStatement is true). The or()/endOr() API only supports a single level of OR grouping, so nested or() calls are rejected. This prevents accidentally building an OR-of-OR query the engine cannot express.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/HistoricPlanItemInstanceQueryImpl.java:812
@Override
public HistoricPlanItemInstanceQuery orderByTerminatedTime() {
return orderBy(HistoricPlanItemInstanceQueryProperty.TERMINATED_TIME);
}
@Override
public HistoricPlanItemInstanceQuery orderByExitTime() {
return orderBy(HistoricPlanItemInstanceQueryProperty.EXIT_TIME);
}
@Override
public HistoricPlanItemInstanceQuery orderByName() {
return orderBy(HistoricPlanItemInstanceQueryProperty.NAME);
}
@Override
public HistoricPlanItemInstanceQuery or() {
if (inOrStatement) {
throw new FlowableIllegalArgumentException("The query is already in an or statement");
}
inOrStatement = true;
if (commandContext != null) {
currentOrQueryObject = new HistoricPlanItemInstanceQueryImpl(commandContext);
} else {
currentOrQueryObject = new HistoricPlanItemInstanceQueryImpl(commandExecutor);
}
orQueryObjects.add(currentOrQueryObject);
return this;
}
@Override
public HistoricPlanItemInstanceQuery endOr() {
if (!inOrStatement) {
throw new FlowableIllegalArgumentException("endOr() can only be called after calling or()");
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Call endOr() before calling or() again
- Restructure the query so all OR conditions are within a single or()...endOr() block
- If multiple independent OR groups are needed, run separate queries and merge results
- Use a flag or loop restructure so or() is invoked exactly once per query
Example fix
// before
query.or().planItemInstanceName("a").or().planItemInstanceName("b"); // throws
// after
query.or().planItemInstanceName("a").planItemInstanceName("b").endOr(); Defensive patterns
Strategy: validation
Validate before calling
boolean canStartOrBlock(HistoricPlanItemInstanceQuery query) {
// track your own flag; the query does not expose inOrStatement
return !orBlockOpen;
} Try / catch
try {
query.or();
} catch (FlowableIllegalArgumentException e) {
// already inside an or() block — close it with endOr() first or skip this or() call
} Prevention
- Track or-block state with a boolean when building queries dynamically
- Always pair or()/endOr() in the same builder method or use try/finally semantics
- Do not call or() inside loops that add OR conditions — call it once before the loop
When it happens
Trigger: Calling or() twice without an intervening endOr(), e.g. chaining or() ... or() while building the query, or re-entering or() due to a loop over filter conditions that each call or().
Common situations: Building dynamic queries in loops where each condition calls or() but endOr() is only called once; copy-pasting query-builder code from examples that already used or().
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- endOr() can only be called after calling or()
- The query is already in an or statement
- endOr() can only be called after calling or()
- the query is already in an or statement
- endOr() can only be called after calling or()
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/dbab8ffa7e54a97e.
Report an issue: GitHub.