{"record":{"id":"53433e3bf749629c","repo":"flowable/flowable-engine","slug":"endor-can-only-be-called-after-calling-or-53433e","errorCode":null,"errorMessage":"endOr() can only be called after calling or()","messagePattern":"endOr\\(\\) can only be called after calling or\\(\\)","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":1172,"sourceCode":"    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\n        inOrStatement = false;\n        currentOrQueryObject = null;\n        return this;\n    }\n\n    @Override\n    public PlanItemInstanceQuery includeLocalVariables() {\n        this.includeLocalVariables = true;\n        return this;\n    }\n\n    @Override\n    public PlanItemInstanceQuery locale(String locale) {\n        this.locale = locale;\n        return this;\n    }","sourceCodeStart":1154,"sourceCodeEnd":1190,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/PlanItemInstanceQueryImpl.java#L1154-L1190","documentation":"Query state-machine violation in PlanItemInstanceQueryImpl.endOr: endOr() was called while no or() block was open (inOrStatement false). The or()/endOr() pairing is unbalanced, indicating a malformed query chain rather than a data problem.","triggerScenarios":"Calling endOr() without a preceding or(); calling endOr() twice; unbalanced or/endOr in dynamically assembled queries.","commonSituations":"String/rule-driven query builders emitting unbalanced or/endOr tokens; error paths that call endOr() in a finally block after or() was never reached.","solutions":["Remove the stray endOr() call, or add the matching or() before it.","Ensure or()/endOr() pairs are balanced and nested code paths cannot skip the or() call.","Use try/finally only around code that is guaranteed to have called or() first."],"exampleFix":"// before\nquery.planItemInstanceState(\"active\").endOr(); // no or() opened\n// after\nquery.or().planItemInstanceState(\"active\").endOr();","handlingStrategy":"validation","validationCode":"boolean inOr = false; // set true after or(), false after endOr(); call endOr() only when inOr","typeGuard":null,"tryCatchPattern":"try { query.endOr(); } catch (FlowableIllegalArgumentException e) { throw new IllegalStateException(\"endOr() without matching or()\", e); }","preventionTips":["Keep or()/endOr() calls lexically adjacent in the same method.","Avoid calling endOr() in finally blocks that may run before or() executes."],"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"}