flowable/flowable-engine · error · FlowableIllegalStateException

Can only enable a plan item instance which is in state AVAIL

Error message

Can only enable a plan item instance which is in state AVAILABLE or DISABLED

What it means

FlowableIllegalStateException thrown by EnablePlanItemInstanceCmd.internalExecute when the plan item instance is neither in AVAILABLE nor DISABLED state. Only available (e.g. waiting human task) or disabled plan items can be enabled. This is a lifecycle state guard.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/EnablePlanItemInstanceCmd.java:44

 */
public class EnablePlanItemInstanceCmd extends AbstractNeedsPlanItemInstanceCmd {

    public EnablePlanItemInstanceCmd(String planItemInstanceId) {
        super(planItemInstanceId);
    }

    public EnablePlanItemInstanceCmd(String planItemInstanceId, Map<String, Object> variables,
            Map<String, Object> formVariables, String formOutcome, FormInfo formInfo,
            Map<String, Object> localVariables, Map<String, Object> transientVariables) {
        
        super(planItemInstanceId, variables, formVariables, formOutcome, formInfo, localVariables, transientVariables);
    }

    @Override
    protected void internalExecute(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity) {
        if (!PlanItemInstanceState.AVAILABLE.equals(planItemInstanceEntity.getState())
                && !PlanItemInstanceState.DISABLED.equals(planItemInstanceEntity.getState())) {
            throw new FlowableIllegalStateException("Can only enable a plan item instance which is in state AVAILABLE or DISABLED");
        }
        CommandContextUtil.getAgenda(commandContext).planEnablePlanItemInstanceOperation(planItemInstanceEntity, null);
    }
    
}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Check the plan item state via PlanItemInstanceQuery and only enable when state is AVAILABLE or DISABLED
  2. Catch FlowableIllegalStateException and treat as idempotent no-op
  3. Refresh UI/model state before allowing enable actions

Example fix

// before
planItemInstanceService.enablePlanItemInstance(planItemInstanceId);
// after
PlanItemInstance pii = cmmnRuntimeService.createPlanItemInstanceQuery()
        .planItemInstanceId(planItemInstanceId).singleResult();
if (pii != null && (PlanItemInstanceState.AVAILABLE.equals(pii.getState())
        || PlanItemInstanceState.DISABLED.equals(pii.getState()))) {
    planItemInstanceService.enablePlanItemInstance(planItemInstanceId);
}
Defensive patterns

Strategy: validation

Validate before calling

PlanItemInstance pii = cmmnRuntimeService.createPlanItemInstanceQuery().planItemInstanceId(id).singleResult(); boolean ok = pii != null && (PlanItemInstanceState.AVAILABLE.equals(pii.getState()) || PlanItemInstanceState.DISABLED.equals(pii.getState())); if (!ok) return;

Type guard

boolean canEnable = pii != null && (PlanItemInstanceState.AVAILABLE.equals(pii.getState()) || PlanItemInstanceState.DISABLED.equals(pii.getState()));

Try / catch

try { planItemInstanceService.enablePlanItemInstance(id); } catch (FlowableIllegalStateException e) { log.info("plan item {} cannot be enabled from current state", id); }

Prevention

When it happens

Trigger: Calling enablePlanItemInstance on a plan item that is active, completed, in progress, or already enabled.

Common situations: UI enable button pressed twice; concurrent state change by another user or async job; stale plan item id after the case advanced; scripted test enabling an item that auto-started.

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/773739731bec2226. Report an issue: GitHub.