flowable/flowable-engine · error · FlowableIllegalStateException
Can only trigger a plan item that is in the ACTIVE state
Error message
Can only trigger a plan item that is in the ACTIVE state
What it means
ProcessTaskActivityBehavior.trigger() is invoked to complete/notify a process task plan item, but the plan item is not in the ACTIVE state, so triggering it is illegal. Flowable throws FlowableIllegalStateException to protect the state machine of the case execution.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/ProcessTaskActivityBehavior.java:163
processInstanceService.deleteProcessInstance(processInstanceId);
FaultPropagation.propagateFault(businessError, commandContext, planItemInstanceEntity);
return;
}
} else {
processInstanceService.startProcessInstance(processDefinitionId, processInstanceId, planItemInstanceEntity.getStageInstanceId(),
planItemInstanceEntity.getTenantId(), inParametersMap, businessKey, variableFormVariables, variableFormInfo, variableFormOutcome);
}
if (!blocking) {
CommandContextUtil.getAgenda(commandContext).planCompletePlanItemInstanceOperation(planItemInstanceEntity);
}
}
@Override
public void trigger(CommandContext commandContext, PlanItemInstanceEntity planItemInstance) {
if (!PlanItemInstanceState.ACTIVE.equals(planItemInstance.getState())) {
throw new FlowableIllegalStateException("Can only trigger a plan item that is in the ACTIVE state");
}
if (planItemInstance.getReferenceId() == null) {
throw new FlowableIllegalStateException("Cannot trigger process task plan item instance : no reference id set");
}
if (!ReferenceTypes.PLAN_ITEM_CHILD_PROCESS.equals(planItemInstance.getReferenceType())) {
throw new FlowableException("Cannot trigger process task plan item instance : reference type '"
+ planItemInstance.getReferenceType() + "' not supported for " + planItemInstance);
}
// Need to be set before planning the complete operation
CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
CaseInstanceEntity caseInstance = cmmnEngineConfiguration.getCaseInstanceEntityManager().findById(planItemInstance.getCaseInstanceId());
handleOutParameters(planItemInstance, caseInstance, cmmnEngineConfiguration.getProcessInstanceService());
// Triggering the plan item (as opposed to a regular complete) terminates the process instance
CommandContextUtil.getAgenda(commandContext).planCompletePlanItemInstanceOperation(planItemInstance);
deleteProcessInstance(commandContext, planItemInstance);
}View on GitHub (pinned to d6d39ce1c6)
Solutions
- Check planItemInstance.getState() equals PlanItemInstanceState.ACTIVE before calling trigger/completion APIs
- Guard the child-process completion callback so it is idempotent and skips plan items already completed/terminated
- Use CmmnRuntimeService.createPlanItemInstanceQuery() to fetch the current state from the DB rather than a stale in-memory object
- If termination races are expected, catch FlowableIllegalStateException around the trigger call and treat it as already-finalized
Example fix
// before
runtimeService.completePlanItemInstance(planItemId); // may throw if not ACTIVE
// after
PlanItemInstance pii = runtimeService.createPlanItemInstanceQuery().planItemInstanceId(planItemId).singleResult();
if (pii != null && PlanItemInstanceState.ACTIVE.equals(pii.getState())) {
runtimeService.completePlanItemInstance(planItemId);
} Defensive patterns
Strategy: type-guard
Validate before calling
PlanItemInstance pii = runtimeService.createPlanItemInstanceQuery()
.planItemInstanceId(planItemId).singleResult();
boolean triggerable = pii != null && "active".equals(pii.getState()); Type guard
function isActive(pii) { return pii != null && 'active' === pii.getState(); } Try / catch
try {
runtimeService.completePlanItemInstance(planItemId);
} catch (FlowableIllegalStateException e) {
// plan item already finalized (completed/terminated); treat as idempotent no-op
} Prevention
- Fetch fresh state from runtime service before triggering
- Make completion callbacks idempotent
- Avoid triggering async process tasks manually
- Watch for termination races between case exit and child completion
When it happens
Trigger: Calling CmmnRuntimeService/PlanItemInstance trigger (e.g. completePlanItemInstance or a child-process completion callback) on a plan item whose state is AVAILABLE, ENABLED, COMPLETED, TERMINATED, etc.
Common situations: Race condition where the child process finished after the case was already terminated or the plan item completed; double-completion from an event/callback listener; manually triggering an async process task that has not yet become active.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot trigger process task plan item instance : no referenc
- Can only disable a plan item instance which is in state ENAB
- Can only enable a plan item instance which is in state AVAIL
- Plan item instance for {eventSubscription} can not be found
- Could not find plan item instance for plan item with definit
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/7511fa1bbcf55bed.
Report an issue: GitHub.