{"record":{"id":"4bc72c030ce440f7","repo":"flowable/flowable-engine","slug":"main-execution-was-a-not-a-decision-service","errorCode":null,"errorMessage":"Main execution was a not a decision service","messagePattern":"Main execution was a not a decision service","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/DmnDecisionServiceImpl.java","lineNumber":234,"sourceCode":"        if (executeDecisionContext.getDmnElement() instanceof DecisionService decisionService) {\n            Map<String, List<Map<String, Object>>> decisionServiceResult = new HashMap<>();\n            DecisionServiceExecutionAuditContainer decisionServiceExecutionAuditContainer = (DecisionServiceExecutionAuditContainer) executeDecisionContext.getDecisionExecution();\n\n            boolean multipleResults = decisionService.getOutputDecisions().size() > 1;\n            for (DmnElementReference elementReference : decisionService.getOutputDecisions()) {\n                DecisionExecutionAuditContainer childDecisionExecution = decisionServiceExecutionAuditContainer\n                        .getChildDecisionExecution(elementReference.getParsedId());\n                if (childDecisionExecution.getDecisionResult() != null && !childDecisionExecution.getDecisionResult().isEmpty()) {\n                    decisionServiceResult.put(elementReference.getParsedId(), childDecisionExecution.getDecisionResult());\n                }\n                multipleResults = multipleResults || childDecisionExecution.isMultipleResults();\n            }\n\n            decisionServiceExecutionAuditContainer.setDecisionServiceResult(decisionServiceResult);\n            decisionServiceExecutionAuditContainer.setMultipleResults(multipleResults);\n            return decisionServiceResult;\n        } else {\n            throw new FlowableException(\"Main execution was a not a decision service\");\n        }\n    }\n\n    protected DecisionExecutionAuditContainer finalizeDecisionExecutionAudit(ExecuteDecisionContext executeDecisionContext) {\n        DecisionExecutionAuditContainer decisionExecution = executeDecisionContext.getDecisionExecution();\n\n        decisionExecution.stopAudit(configuration.getClock().getCurrentTime());\n\n        if (!executeDecisionContext.isDisableHistory()) {\n            commandExecutor.execute(new PersistHistoricDecisionExecutionCmd(executeDecisionContext));\n        }\n\n        return decisionExecution;\n    }\n}\n","sourceCodeStart":216,"sourceCodeEnd":250,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-dmn-engine/src/main/java/org/flowable/dmn/engine/impl/DmnDecisionServiceImpl.java#L216-L250","documentation":"composeDecisionServiceResult is only valid when the main execution was a decision service. If the ExecuteDecisionContext was not executed as a decision service, Flowable throws this FlowableException because composing a decision-service result is impossible.","triggerScenarios":"Calling composeDecisionServiceResult (directly or via decisionResult/executeDecisionServiceWithAuditTrail) with a context that executed a plain Decision instead of a DecisionService, or a mis-built internal context.","commonSituations":"Mixing single-decision evaluation APIs with decision-service result composition; calling internal protected methods in a subclass against the wrong element type; version mismatches where an API changed semantics.","solutions":["Use executeDecisionService/executeDecisionServiceWithSingleResult (or the audit-trail variant) so the execution runs as a decision service","For a plain Decision, use the decision-result APIs (decisionResult/executeWithAuditTrail) instead","If extending the engine, check executeDecisionContext.getDmnElement() instanceof DecisionService before composing"],"exampleFix":"// before\nObject result = decisionService.executeWithAuditTrail(ctx); // ctx wraps a plain Decision\n// after\nif (ctx.getDmnElement() instanceof DecisionService) {\n    result = decisionService.executeDecisionServiceWithAuditTrail(ctx);\n} else {\n    result = decisionService.executeWithAuditTrail(ctx);\n}","handlingStrategy":"type-guard","validationCode":"if (!(ctx.getDmnElement() instanceof DecisionService)) {\n    throw new IllegalArgumentException(\"Context must wrap a DecisionService for this API\");\n}","typeGuard":"boolean isDecisionService(ExecuteDecisionContext ctx) {\n    return ctx != null && ctx.getDmnElement() instanceof DecisionService;\n}","tryCatchPattern":"try {\n    result = decisionService.executeDecisionServiceWithAuditTrail(ctx);\n} catch (FlowableException e) {\n    if (e.getMessage().contains(\"Main execution was a not a decision service\")) { /* use plain-decision APIs instead */ }\n    throw e;\n}","preventionTips":["Match the API to the element type: decision-service APIs for DecisionService, decision APIs for Decision","Check getDmnElement() before choosing a composition path in subclasses","Avoid calling protected compose* helpers outside their intended element type"],"tags":["dmn","decision-service","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-18T11:17:12.947Z"}