{"record":{"id":"45ff84b05dfdfea8","repo":"flowable/flowable-engine","slug":"can-only-trigger-a-plan-item-that-is-in-the-active-45ff84","errorCode":null,"errorMessage":"Can only trigger a plan item that is in the ACTIVE state","messagePattern":"Can only trigger a plan item that is in the ACTIVE state","errorType":"exception","errorClass":"FlowableIllegalStateException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/CaseTaskActivityBehavior.java","lineNumber":166,"sourceCode":"        planItemInstanceEntity.setReferenceType(ReferenceTypes.PLAN_ITEM_CHILD_CASE);\n        planItemInstanceEntity.setReferenceId(caseInstanceEntity.getId());\n\n        if (variablesFromFormSubmission != null && !variablesFromFormSubmission.isEmpty()) {\n            // The variablesFromFormSubmission can only be non null if there was formInfo\n            cmmnEngineConfiguration.getFormFieldHandler()\n                    .handleFormFieldsOnSubmit(variableInfo.formInfo, null, null, caseInstanceEntity.getId(), ScopeTypes.CMMN,\n                            variablesFromFormSubmission, caseInstanceEntity.getTenantId());\n        }\n\n        if (!blocking) {\n            CommandContextUtil.getAgenda(commandContext).planCompletePlanItemInstanceOperation(planItemInstanceEntity);\n        }\n    }\n\n    @Override\n    public void trigger(CommandContext commandContext, PlanItemInstanceEntity planItemInstance) {\n        if (!PlanItemInstanceState.ACTIVE.equals(planItemInstance.getState())) {\n            throw new FlowableIllegalStateException(\"Can only trigger a plan item that is in the ACTIVE state\");\n        }\n        if (planItemInstance.getReferenceId() == null) {\n            throw new FlowableIllegalStateException(\"Cannot trigger case task plan item instance : no reference id set\");\n        }\n        if (!ReferenceTypes.PLAN_ITEM_CHILD_CASE.equals(planItemInstance.getReferenceType())) {\n            throw new FlowableIllegalStateException(\"Cannot trigger case task plan item instance : reference type '\"\n                    + planItemInstance.getReferenceType() + \"' not supported\");\n        }\n\n        // load the case instance referenced by this case task plan item to check its current state\n        CaseInstanceEntity caseInstance = CommandContextUtil.getCaseInstanceEntityManager(commandContext).findById(planItemInstance.getReferenceId());\n\n        if (caseInstance != null) {\n            // Out parameters are handled here only when the case is still active (manual trigger scenario).\n            // When the child case completed normally, out parameters are already handled\n            // in ChildCaseInstanceStateChangeCallback before the child case gets deleted.\n            handleOutParameters(commandContext, planItemInstance);\n","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/CaseTaskActivityBehavior.java#L148-L184","documentation":"CaseTaskActivityBehavior.trigger is invoked when the case task plan item is completed (e.g. the child case finishes or the task is completed programmatically). It requires the plan item instance to still be in the ACTIVE state before completing it; otherwise this error is thrown to protect the lifecycle.","triggerScenarios":"Completing/triggering a case task plan item instance whose state is not ACTIVE — e.g. the plan item was already terminated, completed by the child case exit, or completed twice concurrently.","commonSituations":"Child case exit criteria terminating the case task while another thread completes it; calling triggerPlanItemInstance on a case task after the child case already ended; race between exit sentry and completion.","solutions":["Check planItemInstance state == ACTIVE before triggering/completing the case task.","Ensure exit criteria on the stage do not both terminate the plan item and complete it.","Avoid double-completion: rely on the child case completion to complete the plan item, or guard programmatic triggers.","Fetch a fresh plan item instance state right before triggering to avoid stale-state races."],"exampleFix":"// before\nruntimeService.triggerPlanItemInstance(caseTaskPii.getId()); // may double-complete\n// after\nPlanItemInstance pii = runtimeService.createPlanItemInstanceQuery()\n    .planItemInstanceId(caseTaskPii.getId()).singleResult();\nif (PlanItemInstanceState.ACTIVE.equals(pii.getState())) {\n    runtimeService.triggerPlanItemInstance(pii.getId());\n}","handlingStrategy":"validation","validationCode":"PlanItemInstance pii = cmmnRuntimeService.createPlanItemInstanceQuery().planItemInstanceId(id).singleResult();\nboolean canComplete = pii != null && PlanItemInstanceState.ACTIVE.equals(pii.getState());","typeGuard":null,"tryCatchPattern":"try {\n    cmmnRuntimeService.triggerPlanItemInstance(id);\n} catch (FlowableIllegalStateException e) {\n    // plan item not ACTIVE — likely already completed/terminated; ignore if idempotent\n}","preventionTips":["Check state == ACTIVE before triggering case tasks","Avoid concurrent completion and exit-criteria termination on the same plan item","Make completion logic idempotent","Let the child case completion drive the case task completion when possible"],"tags":["cmmn","case-task","state-machine","double-completion"],"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-14T05:17:10.506Z"}