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
TriggerPlanItemInstanceOperation moves a plan item instance forward only when its state is ACTIVE. If it is not, Flowable checks whether the plan item is an EventListener and throws a slightly different message; otherwise it throws this generic state error. It guards the CMMN lifecycle so only active (running) plan items can be triggered.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/operation/TriggerPlanItemInstanceOperation.java:47
public TriggerPlanItemInstanceOperation(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity) {
super(commandContext, planItemInstanceEntity);
}
@Override
public void run() {
if (PlanItemInstanceState.ACTIVE.equals(planItemInstanceEntity.getState())
|| (planItemInstanceEntity.getPlanItem() != null
&& planItemInstanceEntity.getPlanItem().getPlanItemDefinition() instanceof EventListener
&& PlanItemInstanceState.AVAILABLE.equals(planItemInstanceEntity.getState()))){
executeTrigger();
} else {
if (planItemInstanceEntity.getPlanItem() != null && planItemInstanceEntity.getPlanItem().getPlanItemDefinition() instanceof EventListener){
throw new FlowableIllegalStateException("Can only trigger an event listener plan item that is in the AVAILABLE state");
} else {
throw new FlowableIllegalStateException("Can only trigger a plan item that is in the ACTIVE state");
}
}
}
protected void executeTrigger() {
Object behaviorObject = planItemInstanceEntity.getPlanItem().getBehavior();
if (!(behaviorObject instanceof CmmnTriggerableActivityBehavior)) {
throw new FlowableException("Cannot trigger a plan item which activity behavior does not implement the "
+ CmmnTriggerableActivityBehavior.class + " interface in " + planItemInstanceEntity);
}
CmmnTriggerableActivityBehavior behavior = (CmmnTriggerableActivityBehavior) planItemInstanceEntity.getPlanItem().getBehavior();
if (behavior instanceof CoreCmmnTriggerableActivityBehavior) {
((CoreCmmnTriggerableActivityBehavior) behavior).trigger(commandContext, planItemInstanceEntity);
} else {
behavior.trigger(planItemInstanceEntity);
}
}View on GitHub (pinned to d6d39ce1c6)
Solutions
- Query the plan item instance state via PlanItemInstanceQuery and only trigger when state equals ACTIVE.
- If the plan item is an event listener, use the appropriate event-trigger API (it must be AVAILABLE, not ACTIVE).
- Re-fetch the current plan item instance id instead of reusing a cached/stale id.
- Register a plan item listener or use case stage transitions instead of manual triggering for non-active items.
Example fix
// before
runtimeService.triggerPlanItemInstance(planItemId); // throws if not ACTIVE
// after
PlanItemInstance pii = runtimeService.createPlanItemInstanceQuery()
.planItemInstanceId(planItemId).singleResult();
if (PlanItemInstanceState.ACTIVE.equals(pii.getState())) {
runtimeService.triggerPlanItemInstance(planItemId);
} Defensive patterns
Strategy: validation
Validate before calling
PlanItemInstance pii = cmmnRuntimeService.createPlanItemInstanceQuery().planItemInstanceId(id).singleResult(); boolean canTrigger = pii != null && PlanItemInstanceState.ACTIVE.equals(pii.getState());
Try / catch
try {
cmmnRuntimeService.triggerPlanItemInstance(id);
} catch (FlowableIllegalStateException e) {
// re-query state; plan item is not ACTIVE — skip or log
} Prevention
- Always query the plan item state before triggering
- Never cache plan item ids across case lifecycle changes
- Use event listeners' dedicated trigger APIs instead of generic trigger
- Centralize trigger calls in a service that checks state
When it happens
Trigger: Calling PlanItemInstanceRuntimeService.triggerPlanItemInstance(planItemInstanceId) for a plan item whose state is not ACTIVE (e.g. AVAILABLE, COMPLETED, TERMINATED); or an agenda operation invoking run() on a stale/non-active plan item instance.
Common situations: Triggering an already-completed human task or milestone; triggering an event-listener plan item (gets the sibling AVAILABLE-state message instead); stale references to a plan item id from a previous case execution; retrying a trigger after the case moved on.
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
- Plan item instance id is null
- Cannot find plan item instance for id ${planItemInstanceId}
- Cannot find plan item instance with id
- planItemInstanceId is null
- plan item instance ${planItemInstanceId} doesn't exist
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/36340be90b57b45a.
Report an issue: GitHub.