{"record":{"id":"edea5d89b34d5102","repo":"flowable/flowable-engine","slug":"the-query-is-already-in-an-or-statement-edea5d","errorCode":null,"errorMessage":"the query is already in an or statement","messagePattern":"the query is already in an or statement","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/HistoricProcessInstanceQueryImpl.java","lineNumber":1116,"sourceCode":"        return this;\n    }\n    \n    @Override\n    public HistoricProcessInstanceQuery withoutSorting() {\n        this.withoutSorting = true;\n        return this;\n    }\n    \n    @Override\n    public HistoricProcessInstanceQuery returnIdsOnly() {\n        this.returnIdsOnly = true;\n        return this;\n    }\n\n    @Override\n    public HistoricProcessInstanceQuery 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 HistoricProcessInstanceQueryImpl(commandContext, processEngineConfiguration);\n        } else {\n            currentOrQueryObject = new HistoricProcessInstanceQueryImpl(commandExecutor, processEngineConfiguration);\n        }\n        orQueryObjects.add(currentOrQueryObject);\n        return this;\n    }\n\n    @Override\n    public HistoricProcessInstanceQuery endOr() {\n        if (!inOrStatement) {\n            throw new FlowableException(\"endOr() can only be called after calling or()\");\n        }\n","sourceCodeStart":1098,"sourceCodeEnd":1134,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/HistoricProcessInstanceQueryImpl.java#L1098-L1134","documentation":"Flowable throws this FlowableException from HistoricProcessInstanceQuery.or() when the query is already inside an OR statement. OR blocks cannot be nested; or() may only be called from the top-level query state. The flag inOrStatement tracks whether an or() block is currently open.","triggerScenarios":"Calling query.or() twice without an intervening endOr(), e.g. building query.or().or() or re-entering or() inside an open or-block.","commonSituations":"Programmatic query builders that append or() per filter condition without tracking whether an or-block is already open; copying example code that mixes or/endOr incorrectly.","solutions":["Call endOr() before starting a new or() block","Restructure the query so each or() ... endOr() block is closed before another opens","Track the open state in your builder code and only emit or() at top level"],"exampleFix":"// before\nquery.or().processInstanceBusinessKey(\"a\");\nquery.or().processInstanceBusinessKey(\"b\");\n// after\nquery.or().processInstanceBusinessKey(\"a\").endOr();\nquery.or().processInstanceBusinessKey(\"b\").endOr();","handlingStrategy":"validation","validationCode":"boolean inOrBlock = false;\nvoid safeOr(HistoricProcessInstanceQuery q) {\n    if (inOrBlock) { q.endOr(); }\n    q.or();\n    inOrBlock = true;\n}","typeGuard":"boolean canStartOrBlock(boolean inOrStatement) {\n    return !inOrStatement;\n}","tryCatchPattern":"try {\n    query.or();\n} catch (FlowableException e) {\n    query.endOr();\n    query.or();\n}","preventionTips":["Always pair or() with endOr() in the same code block","Never nest or() inside an open or-block; Flowable OR blocks are not nestable","Centralize or-block construction in a helper that tracks open/closed state"],"tags":["flowable","query-builder","or-statement","invalid-state"],"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"}