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

  1. Query the plan item instance state via PlanItemInstanceQuery and only trigger when state equals ACTIVE.
  2. If the plan item is an event listener, use the appropriate event-trigger API (it must be AVAILABLE, not ACTIVE).
  3. Re-fetch the current plan item instance id instead of reusing a cached/stale id.
  4. 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

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


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/36340be90b57b45a. Report an issue: GitHub.