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
HistoryJobQuery.or() throws FlowableException when the query is already inside an or() block (inOrStatement == true). Flowable query API only supports one level of or-nesting; calling or() twice without an intervening endOr() is an invalid state, so it fails fast.
Solutions
- Call endOr() before starting another or() block
- Restructure so or() is called exactly once, with all OR criteria between or() and endOr()
- Track or-state in query-builder code so or() is only invoked when not already in an or statement
- If criteria must be combined independently, build separate queries and merge results instead of nested or()
Example fix
// before query.or().jobId(id1).or().handlerType(type); // second or() throws // after query.or().jobId(id1).handlerType(type).endOr();
Defensive patterns
Strategy: validation
Validate before calling
if (query instanceof AbstractVariableQueryImpl) { /* or-state is internal; guard at builder level */ }
// track in your builder:
// boolean inOr = false;
// assert !inOr : "or() already active"; Try / catch
try {
builder.applyOrCriteria(query);
} catch (FlowableException e) {
if (e.getMessage().contains("already in an or statement")) {
throw new IllegalStateException("Query builder opened or() twice without endOr()", e);
}
throw e;
} Prevention
- Call or()/endOr() exactly once per OR group, wrapping all OR criteria
- Have query-builder helpers accept a single boolean 'useOr' rather than calling or() themselves
- Never call or() inside a loop without closing the previous block
When it happens
Trigger: Calling query.or()...or() without calling endOr() in between, or building the query in a loop/helper where or() is invoked per filter without tracking the current or-state.
Common situations: Composing query filters programmatically where each filter helper calls or(); copying example code that already opened an or block; retry/rebuild logic that re-applies criteria to the same query object that is still in an or statement.
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()
- endOr() can only be called after calling or()
- endOr() can only be called after calling or()
- endOr() can only be called after calling or()
- endOr() can only be called after calling or()
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/e5906016a38d4708.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/HistoryJobQueryImpl.java:227
this.onlyUnlocked = true;
}
return this;
}
@Override
public HistoryJobQuery withoutScopeType() {
if (inOrStatement) {
this.currentOrQueryObject.withoutScopeType = true;
} else {
this.withoutScopeType = true;
}
return this;
}
@Override
public HistoryJobQuery or() {
if (inOrStatement) {
throw new FlowableException("the query is already in an or statement");
}
inOrStatement = true;
if (commandContext != null) {
currentOrQueryObject = new HistoryJobQueryImpl(commandContext, jobServiceConfiguration);
} else {
currentOrQueryObject = new HistoryJobQueryImpl(commandExecutor, jobServiceConfiguration);
}
orQueryObjects.add(currentOrQueryObject);
return this;
}
@Override
public HistoryJobQuery endOr() {
if (!inOrStatement) {
throw new FlowableException("endOr() can only be called after calling or()");
}
inOrStatement = false;
currentOrQueryObject = null;View on GitHub (pinned to d6d39ce1c6)