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

CaseInstanceQueryImpl.or() throws FlowableException when the query is already inside an or() block. Flowable supports only a single, flat OR block per query — nested or sequential or() calls without a matching endOr() are not supported.

Solutions

  1. Call endOr() before starting another or() block, or restructure so all OR conditions are added within a single or()...endOr() section.
  2. Remove the second or() call and add the extra conditions inside the existing OR block.
  3. In loop-based builders, call or() once before the loop and endOr() after it.
  4. Chain queries with FlowableOrQueryObject semantics only where the API allows; otherwise run multiple queries and merge results in application code.

Example fix

// before
query.or().caseDefinitionKey("A").or().caseDefinitionKey("B"); // second or() throws
// after
query.or().caseDefinitionKey("A").caseDefinitionKey("B").endOr();
Defensive patterns

Strategy: try-catch

Validate before calling

if (query instanceof CaseInstanceQueryImpl && ((CaseInstanceQueryImpl) query).inOrStatement) {
    throw new IllegalStateException("or() already active; call endOr() first");
}
query.or();

Try / catch

try {
    query.or();
} catch (FlowableException e) {
    if (e.getMessage().contains("already in an or statement")) {
        log.warn("Duplicate or() ignored");
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling query.or() twice without an intervening endOr(); building the query in a loop that calls or() per filter condition; combining multiple filter builders that each open an or() block on the same query object.

Common situations: Dynamic query builders accumulating 'any of these' conditions in a loop; copy-pasted filter code that opens or() at multiple levels; framework integrations layering or() blocks from different filter sources.

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/aa593ff00cb57e7c. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/CaseInstanceQueryImpl.java:873

    public CaseInstanceQuery involvedGroups(Set<String> groupIds) {
        if (groupIds == null) {
            throw new FlowableIllegalArgumentException("involvedGroups are null");
        }
        if (groupIds.isEmpty()) {
            throw new FlowableIllegalArgumentException("involvedGroups are empty");
        }
        if (inOrStatement) {
            this.currentOrQueryObject.involvedGroups = groupIds;
        } else {
            this.involvedGroups = groupIds;
        }
        return this;
    }

    @Override
    public CaseInstanceQuery or() {
        if (inOrStatement) {
            throw new FlowableException("the query is already in an or statement");
        }

        inOrStatement = true;
        if (commandContext != null) {
            currentOrQueryObject = new CaseInstanceQueryImpl(commandContext, cmmnEngineConfiguration);
        } else {
            currentOrQueryObject = new CaseInstanceQueryImpl(commandExecutor, cmmnEngineConfiguration);
        }
        orQueryObjects.add(currentOrQueryObject);
        return this;
    }

    @Override
    public CaseInstanceQuery endOr() {
        if (!inOrStatement) {
            throw new FlowableException("endOr() can only be called after calling or()");
        }

View on GitHub (pinned to d6d39ce1c6)