{"record":{"id":"b7b609cd0571fbe1","repo":"flowable/flowable-engine","slug":"the-query-is-already-in-an-or-statement-b7b609","errorCode":null,"errorMessage":"the query is already in an or statement","messagePattern":"the query is already in an or statement","errorType":"validation","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/ExecutionQueryImpl.java","lineNumber":980,"sourceCode":"    @Override\n    public ExecutionQuery startedBy(String userId) {\n        if (userId == null) {\n            throw new FlowableIllegalArgumentException(\"user id is null\");\n        }\n        \n        if (inOrStatement) {\n            currentOrQueryObject.startedBy = userId;\n        } else {\n            this.startedBy = userId;\n        }\n\n        return this;\n    }\n    \n    @Override\n    public ExecutionQuery or() {\n        if (inOrStatement) {\n            throw new FlowableException(\"the query is already in an or statement\");\n        }\n\n        inOrStatement = true;\n        if (commandContext != null) {\n            currentOrQueryObject = new ExecutionQueryImpl(commandContext, processEngineConfiguration);\n        } else {\n            currentOrQueryObject = new ExecutionQueryImpl(commandExecutor, processEngineConfiguration);\n        }\n        orQueryObjects.add(currentOrQueryObject);\n        return this;\n    }\n\n    @Override\n    public ExecutionQuery endOr() {\n        if (!inOrStatement) {\n            throw new FlowableException(\"endOr() can only be called after calling or()\");\n        }\n","sourceCodeStart":962,"sourceCodeEnd":998,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/ExecutionQueryImpl.java#L962-L998","documentation":"ExecutionQueryImpl.or() opens an OR block in the query but cannot be nested; calling or() while already inside an or statement throws FlowableException. Flowable query API supports only one flat or() ... endOr() block per query.","triggerScenarios":"Calling query.or() twice without an intervening endOr(), e.g. building criteria in a loop that adds or() per condition, or concatenating two query-builder fragments that each start with or().","commonSituations":"Dynamic query builders that append or() unconditionally for each optional filter; reusable filter helper methods that each call or() internally.","solutions":["Call or() once, then chain multiple conditions inside the block, and close with endOr()","Track an inOr flag in your builder so or() is only emitted when not already inside an OR block","Refactor conditions that require nested ORs into two separate queries and merge/union the results in application code"],"exampleFix":"// before\nquery.or().processDefinitionKey(\"k1\").or().processDefinitionKey(\"k2\").endOr();\n\n// after\nquery.or().processDefinitionKey(\"k1\").processDefinitionKey(\"k2\").endOr();","handlingStrategy":"validation","validationCode":"if (!builder.isInsideOrBlock()) {\n    builder.openOr();\n}","typeGuard":null,"tryCatchPattern":"try {\n    query.or();\n} catch (FlowableException e) {\n    if (!e.getMessage().contains(\"already in an or statement\")) throw e;\n    // continue adding conditions inside the existing OR block\n}","preventionTips":["Call or() exactly once per query, then chain all OR conditions before endOr()","Never emit or() inside loops of optional criteria","Encapsulate OR building in a helper that tracks open/close state"],"tags":["flowable","query","or-statement","invalid-state","java"],"backgroundTag":"invalid-state-transition","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}