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
PlanItemInstanceQueryImpl.or() throws FlowableIllegalArgumentException if the query is already inside an or() block (inOrStatement is true). or() / endOr() must strictly alternate; nested or-expressions are not supported.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/PlanItemInstanceQueryImpl.java:1156
variableExists(name, false);
}
return this;
}
@Override
public PlanItemInstanceQuery caseVariableNotExists(String name) {
if (inOrStatement) {
this.currentOrQueryObject.variableNotExists(name, false);
} else {
variableNotExists(name, false);
}
return this;
}
@Override
public PlanItemInstanceQuery or() {
if (inOrStatement) {
throw new FlowableIllegalArgumentException("The query is already in an or statement");
}
inOrStatement = true;
if (commandContext != null) {
currentOrQueryObject = new PlanItemInstanceQueryImpl(commandContext, cmmnEngineConfiguration);
} else {
currentOrQueryObject = new PlanItemInstanceQueryImpl(commandExecutor, cmmnEngineConfiguration);
}
orQueryObjects.add(currentOrQueryObject);
return this;
}
@Override
public PlanItemInstanceQuery endOr() {
if (!inOrStatement) {
throw new FlowableIllegalArgumentException("endOr() can only be called after calling or()");
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Call endOr() before starting a new or() block.
- Track whether the query is already in an or statement and only call or() at the top level.
- Restructure the predicate: combine conditions inside a single or() block instead of nesting.
Example fix
// before
query.or().planItemInstanceDefinitionId("a");
query.or().planItemInstanceDefinitionId("b"); // wrong: already in or
// after
query.or().planItemInstanceDefinitionId("a").planItemInstanceDefinitionId("b").endOr(); Defensive patterns
Strategy: validation
Validate before calling
boolean inOr = query.toString().contains("OR"); // track or() state in your own builder wrapper instead Try / catch
try { query.or(); } catch (FlowableIllegalArgumentException e) { throw new IllegalStateException("Nested or() not allowed; balance or()/endOr()", e); } Prevention
- Wrap query building in a helper that tracks inOr state and calls or()/endOr() in pairs.
- Never emit or() from reusable sub-clauses; compose conditions within one or block.
When it happens
Trigger: Calling or() twice without an intervening endOr(); a shared query-builder method that calls or() while the caller already opened an or block.
Common situations: Programmatic query assembly from a DSL or rules engine where an or() call is generated inside an existing or block; refactored helper methods that append or() clauses unconditionally.
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
- The query is already in an or statement
- endOr() can only be called after calling or()
- 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/65177d5f6eaf22d0.
Report an issue: GitHub.