flowable/flowable-engine · error · FlowableException
the query is already in an or statement
Error message
the query is already in an or statement
What it means
Flowable throws this FlowableException when HistoricTaskInstanceQuery.or() is invoked while the query is already inside an active or-block. Nested or-statements are not supported by the query model, so a second or() before endOr() is rejected. It is a query-usage (state) error raised at build time.
Source
Thrown at modules/flowable-task-service/src/main/java/org/flowable/task/service/impl/HistoricTaskInstanceQueryImpl.java:2066
return this;
}
@Override
public HistoricTaskInstanceQuery includeCaseVariables() {
this.includeCaseVariables = true;
return this;
}
@Override
public HistoricTaskInstanceQuery includeIdentityLinks() {
this.includeIdentityLinks = true;
return this;
}
@Override
public HistoricTaskInstanceQuery or() {
if (inOrStatement) {
throw new FlowableException("the query is already in an or statement");
}
inOrStatement = true;
if (databaseType != null) {
currentOrQueryObject = new HistoricTaskInstanceQueryImpl(commandExecutor, databaseType, taskServiceConfiguration, variableServiceConfiguration);
} else {
currentOrQueryObject = new HistoricTaskInstanceQueryImpl(commandExecutor, taskServiceConfiguration, variableServiceConfiguration);
}
orQueryObjects.add(currentOrQueryObject);
return this;
}
@Override
public HistoricTaskInstanceQuery endOr() {
if (!inOrStatement) {
throw new FlowableException("endOr() can only be called after calling or()");
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Call endOr() to close the current or-block before starting a new one with or().
- Restructure the query so each or-group is opened and closed exactly once (or() ... endOr()).
- Combine the conditions of the second group into the first or-block if they belong together.
- Track the inOr state in your builder helper to avoid calling or() twice.
Example fix
// before
query.or().taskName("a").or().taskName("b").endOr(); // throws
// after
query.or().taskName("a").taskName("b").endOr(); Defensive patterns
Strategy: validation
Validate before calling
boolean inOr = ((HistoricTaskInstanceQueryImpl) query).isInOrStatement(); // guard before or()
if (!inOr) { query.or(); } Try / catch
try {
query.or();
} catch (FlowableException e) {
if (e.getMessage().contains("already in an or statement")) {
throw new IllegalStateException("Query builder misuse: or() called twice before endOr()", e);
}
throw e;
} Prevention
- Always pair or() and endOr() in the same method or block
- Never call or() inside a helper that may itself be invoked within an or-block
- Structure query building linearly instead of conditionally opening or-groups
- Write a unit test for each dynamic query path to catch unbalanced or() early
When it happens
Trigger: Calling query.or() ... query.or() without an intervening endOr(), e.g. chaining two or-groups or accidentally calling or() inside an already open or-block.
Common situations: Building queries programmatically where or()/endOr() are called in loops or helper methods that each open their own or-block; copy-pasted query code where an endOr() was deleted.
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/871eebe6c563b8ed.
Report an issue: GitHub.