{"record":{"id":"533b867347071db2","repo":"flowable/flowable-engine","slug":"cannot-exit-case-with-complete-event-type-as-the","errorCode":null,"errorMessage":"Cannot exit case with 'complete' event type as the case '${caseInstanceId}' is not yet completable. The plan item '${planItemName} (${planItemDefinitionId})' prevented it from completion.","messagePattern":"Cannot exit case with 'complete' event type as the case '(.+?)' is not yet completable\\. The plan item '(.+?) \\((.+?)\\)' prevented it from completion\\.","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/operation/TerminateCaseInstanceOperation.java","lineNumber":82,"sourceCode":"        }\n    }\n\n    /**\n     * Checks, if the case is completable and if not, raises an exception.\n     */\n    protected void checkCaseToBeCompletable() {\n        CaseInstanceEntity caseInstance = getCaseInstanceEntity();\n        boolean isAutoComplete = getPlanModel(caseInstance).isAutoComplete();\n\n        // if the case should exit with a complete event instead of exit, we need to make sure it is completable\n        // we don't use the completion flag directly on the entity as it gets evaluated only at the end of an evaluation cycle which we didn't hit yet\n        // at this point, so we need a proper evaluation of the completion\n        CompletionEvaluationResult completionEvaluationResult = PlanItemInstanceContainerUtil\n            .shouldPlanItemContainerComplete(commandContext, caseInstance, isAutoComplete);\n\n        if (!completionEvaluationResult.isCompletable()) {\n            // we can't complete the case as it is currently not completable, so we need to throw an exception\n            throw new FlowableIllegalArgumentException(\n                \"Cannot exit case with 'complete' event type as the case '\" + getCaseInstanceId() + \"' is not yet completable. The plan item '\" +\n                    completionEvaluationResult.getPlanItemInstance().getName() + \" (\" +\n                    completionEvaluationResult.getPlanItemInstance().getPlanItemDefinitionId() + \")' prevented it from completion.\");\n        }\n    }\n\n    @Override\n    public String getNewState() {\n        // depending on the exit event type, we will end up in the complete state, even though the case was actually terminated / exited\n        if (EXIT_EVENT_TYPE_COMPLETE.equals(exitEventType) || EXIT_EVENT_TYPE_FORCE_COMPLETE.equals(exitEventType)) {\n            return CaseInstanceState.COMPLETED;\n        }\n        return CaseInstanceState.TERMINATED;\n    }\n    \n    @Override\n    public void changeStateForChildPlanItemInstance(PlanItemInstanceEntity planItemInstanceEntity) {\n        // if the plan item implements the specific behavior interface for ending, invoke it, otherwise use the default one which is terminate, regardless,","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/operation/TerminateCaseInstanceOperation.java#L64-L100","documentation":"TerminateCaseInstanceOperation.checkCaseToBeCompletable, invoked during preRunCheck, evaluates whether the case's plan model can complete. When a case is exited with event type 'complete' but a child plan item still prevents completion, the engine refuses with a FlowableIllegalArgumentException naming the blocking plan item.","triggerScenarios":"Manually terminating a case with the 'complete' exit semantics (or an event fires it) while active children (tasks, listeners) still block case completion; isAutoComplete evaluation fails in shouldPlanItemContainerComplete.","commonSituations":"Administrator terminate actions against cases with unfinished human tasks; exit criteria with 'complete' event type misused where plain 'exit' was intended; incomplete milestones.","solutions":["Complete the blocking plan item (shown in the message) before terminating.","Use the plain exit/terminate event type instead of 'complete' when unconditional termination is desired.","Adjust sentry/criteria so case completion is achievable at the point of exit.","Intercept the FlowableIllegalArgumentException in the terminate API call and report the blocking item to the user."],"exampleFix":"// before: <criterion sentryRef=\"killSentry\"> with sentry onEvent=\"complete\"\n// after: unconditional exit\n<sentry id=\"killSentry\">\n  <planItemOnPart sourceRef=\"killSignal\"/>\n</sentry>","handlingStrategy":"try-catch","validationCode":"// java: check blocking active children before 'complete' exit of case\nList<PlanItemInstance> active = cmmnRuntimeService.createPlanItemInstanceQuery()\n    .caseInstanceId(caseInstanceId).planItemInstanceState(\"active\").list();\nif (!active.isEmpty()) throw new IllegalStateException(\"Case has active plan items; complete-exit will fail\");","typeGuard":null,"tryCatchPattern":"try {\n    cmmnRuntimeService.terminateCaseInstance(caseInstanceId);\n} catch (FlowableIllegalArgumentException e) {\n    if (e.getMessage().contains(\"is not yet completable\")) {\n        // prompt user to finish blocking plan item\n    }\n}","preventionTips":["Use unconditional exit sentries for manual termination flows.","Show users the blocking plan item before offering terminate-with-complete.","Define milestones/autocomplete so cases can reach completable state."],"tags":["cmmn","case-instance","state-transition"],"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"}