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 from HistoricProcessInstanceQuery.or() when the query is already inside an OR statement. OR blocks cannot be nested; or() may only be called from the top-level query state. The flag inOrStatement tracks whether an or() block is currently open.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/HistoricProcessInstanceQueryImpl.java:1116
return this;
}
@Override
public HistoricProcessInstanceQuery withoutSorting() {
this.withoutSorting = true;
return this;
}
@Override
public HistoricProcessInstanceQuery returnIdsOnly() {
this.returnIdsOnly = true;
return this;
}
@Override
public HistoricProcessInstanceQuery or() {
if (inOrStatement) {
throw new FlowableException("the query is already in an or statement");
}
inOrStatement = true;
if (commandContext != null) {
currentOrQueryObject = new HistoricProcessInstanceQueryImpl(commandContext, processEngineConfiguration);
} else {
currentOrQueryObject = new HistoricProcessInstanceQueryImpl(commandExecutor, processEngineConfiguration);
}
orQueryObjects.add(currentOrQueryObject);
return this;
}
@Override
public HistoricProcessInstanceQuery endOr() {
if (!inOrStatement) {
throw new FlowableException("endOr() can only be called after calling or()");
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Call endOr() before starting a new or() block
- Restructure the query so each or() ... endOr() block is closed before another opens
- Track the open state in your builder code and only emit or() at top level
Example fix
// before
query.or().processInstanceBusinessKey("a");
query.or().processInstanceBusinessKey("b");
// after
query.or().processInstanceBusinessKey("a").endOr();
query.or().processInstanceBusinessKey("b").endOr(); Defensive patterns
Strategy: validation
Validate before calling
boolean inOrBlock = false;
void safeOr(HistoricProcessInstanceQuery q) {
if (inOrBlock) { q.endOr(); }
q.or();
inOrBlock = true;
} Type guard
boolean canStartOrBlock(boolean inOrStatement) {
return !inOrStatement;
} Try / catch
try {
query.or();
} catch (FlowableException e) {
query.endOr();
query.or();
} Prevention
- Always pair or() with endOr() in the same code block
- Never nest or() inside an open or-block; Flowable OR blocks are not nestable
- Centralize or-block construction in a helper that tracks open/closed state
When it happens
Trigger: Calling query.or() twice without an intervening endOr(), e.g. building query.or().or() or re-entering or() inside an open or-block.
Common situations: Programmatic query builders that append or() per filter condition without tracking whether an or-block is already open; copying example code that mixes or/endOr incorrectly.
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/edea5d89b34d5102.
Report an issue: GitHub.