{"record":{"id":"65177d5f6eaf22d0","repo":"flowable/flowable-engine","slug":"the-query-is-already-in-an-or-statement-65177d","errorCode":null,"errorMessage":"The query is already in an or statement","messagePattern":"The query is already in an or statement","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/PlanItemInstanceQueryImpl.java","lineNumber":1156,"sourceCode":"            variableExists(name, false);\n        }\n        return this;\n    }\n\n    @Override\n    public PlanItemInstanceQuery caseVariableNotExists(String name) {\n        if (inOrStatement) {\n            this.currentOrQueryObject.variableNotExists(name, false);\n        } else {\n            variableNotExists(name, false);\n        }\n        return this;\n    }\n\n    @Override\n    public PlanItemInstanceQuery or() {\n        if (inOrStatement) {\n            throw new FlowableIllegalArgumentException(\"The query is already in an or statement\");\n        }\n\n        inOrStatement = true;\n        if (commandContext != null) {\n            currentOrQueryObject = new PlanItemInstanceQueryImpl(commandContext, cmmnEngineConfiguration);\n        } else {\n            currentOrQueryObject = new PlanItemInstanceQueryImpl(commandExecutor, cmmnEngineConfiguration);\n        }\n        orQueryObjects.add(currentOrQueryObject);\n        return this;\n    }\n\n    @Override\n    public PlanItemInstanceQuery endOr() {\n        if (!inOrStatement) {\n            throw new FlowableIllegalArgumentException(\"endOr() can only be called after calling or()\");\n        }\n","sourceCodeStart":1138,"sourceCodeEnd":1174,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/PlanItemInstanceQueryImpl.java#L1138-L1174","documentation":"PlanItemInstanceQueryImpl.or() throws FlowableIllegalArgumentException if the query is already inside an or() block (inOrStatement is true). or() / endOr() must strictly alternate; nested or-expressions are not supported.","triggerScenarios":"Calling or() twice without an intervening endOr(); a shared query-builder method that calls or() while the caller already opened an or block.","commonSituations":"Programmatic query assembly from a DSL or rules engine where an or() call is generated inside an existing or block; refactored helper methods that append or() clauses unconditionally.","solutions":["Call endOr() before starting a new or() block.","Track whether the query is already in an or statement and only call or() at the top level.","Restructure the predicate: combine conditions inside a single or() block instead of nesting."],"exampleFix":"// before\nquery.or().planItemInstanceDefinitionId(\"a\");\nquery.or().planItemInstanceDefinitionId(\"b\"); // wrong: already in or\n// after\nquery.or().planItemInstanceDefinitionId(\"a\").planItemInstanceDefinitionId(\"b\").endOr();","handlingStrategy":"validation","validationCode":"boolean inOr = query.toString().contains(\"OR\"); // track or() state in your own builder wrapper instead","typeGuard":null,"tryCatchPattern":"try { query.or(); } catch (FlowableIllegalArgumentException e) { throw new IllegalStateException(\"Nested or() not allowed; balance or()/endOr()\", e); }","preventionTips":["Wrap query building in a helper that tracks inOr state and calls or()/endOr() in pairs.","Never emit or() from reusable sub-clauses; compose conditions within one or block."],"tags":["flowable","cmmn","query","or-statement","api-misuse"],"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-14T11:17:12.474Z"}