flowable/flowable-engine · error · FlowableIllegalArgumentException
endOr() can only be called after calling or()
Error message
endOr() can only be called after calling or()
What it means
Query state-machine violation in PlanItemInstanceQueryImpl.endOr: endOr() was called while no or() block was open (inOrStatement false). The or()/endOr() pairing is unbalanced, indicating a malformed query chain rather than a data problem.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/PlanItemInstanceQueryImpl.java:1172
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()");
}
inOrStatement = false;
currentOrQueryObject = null;
return this;
}
@Override
public PlanItemInstanceQuery includeLocalVariables() {
this.includeLocalVariables = true;
return this;
}
@Override
public PlanItemInstanceQuery locale(String locale) {
this.locale = locale;
return this;
}View on GitHub (pinned to d6d39ce1c6)
Solutions
- Remove the stray endOr() call, or add the matching or() before it.
- Ensure or()/endOr() pairs are balanced and nested code paths cannot skip the or() call.
- Use try/finally only around code that is guaranteed to have called or() first.
Example fix
// before
query.planItemInstanceState("active").endOr(); // no or() opened
// after
query.or().planItemInstanceState("active").endOr(); Defensive patterns
Strategy: validation
Validate before calling
boolean inOr = false; // set true after or(), false after endOr(); call endOr() only when inOr
Try / catch
try { query.endOr(); } catch (FlowableIllegalArgumentException e) { throw new IllegalStateException("endOr() without matching or()", e); } Prevention
- Keep or()/endOr() calls lexically adjacent in the same method.
- Avoid calling endOr() in finally blocks that may run before or() executes.
When it happens
Trigger: Calling endOr() without a preceding or(); calling endOr() twice; unbalanced or/endOr in dynamically assembled queries.
Common situations: String/rule-driven query builders emitting unbalanced or/endOr tokens; error paths that call endOr() in a finally block after or() was never reached.
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()
- The query is already in an or statement
- 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/53433e3bf749629c.
Report an issue: GitHub.