flowable/flowable-engine · error · FlowableException
endOr() can only be called after calling or()
Error message
endOr() can only be called after calling or()
What it means
API-misuse guard in ExecutionQueryImpl.endOr: endOr() was invoked while no OR block was open (or() was never called on this query), leaving the query's or-state unbalanced and the fluent chain invalid.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/ExecutionQueryImpl.java:996
public ExecutionQuery or() {
if (inOrStatement) {
throw new FlowableException("the query is already in an or statement");
}
inOrStatement = true;
if (commandContext != null) {
currentOrQueryObject = new ExecutionQueryImpl(commandContext, processEngineConfiguration);
} else {
currentOrQueryObject = new ExecutionQueryImpl(commandExecutor, processEngineConfiguration);
}
orQueryObjects.add(currentOrQueryObject);
return this;
}
@Override
public ExecutionQuery endOr() {
if (!inOrStatement) {
throw new FlowableException("endOr() can only be called after calling or()");
}
inOrStatement = false;
currentOrQueryObject = null;
return this;
}
// ordering ////////////////////////////////////////////////////
@Override
public ExecutionQueryImpl orderByProcessInstanceId() {
this.orderProperty = ExecutionQueryProperty.PROCESS_INSTANCE_ID;
return this;
}
@Override
public ExecutionQueryImpl orderByProcessDefinitionId() {
this.orderProperty = ExecutionQueryProperty.PROCESS_DEFINITION_ID;View on GitHub (pinned to d6d39ce1c6)
Solutions
- Ensure endOr() is only invoked when or() was called earlier on the same query
- Track open/close state in your builder wrapper before emitting endOr()
- Remove stray endOr() calls when the query has no OR criteria
Example fix
// before
query.processDefinitionKey("k1").endOr();
// after
query.or().processDefinitionKey("k1").endOr(); Defensive patterns
Strategy: validation
Validate before calling
if (builder.isInsideOrBlock()) {
builder.closeOr();
} Try / catch
try {
query.endOr();
} catch (FlowableException e) {
if (!e.getMessage().contains("endOr() can only be called after calling or()")) throw e;
// no OR block was open; proceed without closing
} Prevention
- Pair every endOr() with a preceding or() in the same code path
- Avoid conditional or() with unconditional endOr()
- Use try/finally only around an already-opened OR block
When it happens
Trigger: Calling query.endOr() without ever calling or(); calling endOr() twice after a single or(); or copying fragments of builder code where the or() call is conditionally skipped but endOr() always runs.
Common situations: Query assembly code with conditional logic (if (a) or(); if (b) ...) where the or() branch was not taken; accidental duplicate endOr() in chained builders.
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
- the query is already in an or statement
- Deployment id is null
- Deployment ids is null
- deploymentName is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/eaab76838ac2f6f7.
Report an issue: GitHub.