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

  1. Call endOr() before starting another or() block
  2. Restructure so or() is called exactly once, with all OR criteria between or() and endOr()
  3. Track or-state in query-builder code so or() is only invoked when not already in an or statement
  4. 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

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


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)