flowable/flowable-engine · error · FlowableException

multiple active or enabled plan item instances found for pla

Error message

multiple active or enabled plan item instances found for plan item definition <planItemDefinitionId>

What it means

During a plan item state change to AVAILABLE, Flowable expects at most one active or enabled plan item instance per plan item definition mapping. When two or more instances of the same plan item definition are simultaneously active or enabled, the operation is ambiguous, so this FlowableException is thrown.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/AbstractCmmnDynamicStateManager.java:427

                if (planItemDefinitionMapping.getWithLocalVariables() != null && !planItemDefinitionMapping.getWithLocalVariables().isEmpty()) {
                    availablePlanItemInstance.setVariablesLocal(planItemDefinitionMapping.getWithLocalVariables());
                }
                
                CmmnHistoryManager cmmnHistoryManager = cmmnEngineConfiguration.getCmmnHistoryManager();
                cmmnHistoryManager.recordPlanItemInstanceCreated(availablePlanItemInstance);
                
                CmmnEngineAgenda agenda = CommandContextUtil.getAgenda(commandContext);
                agenda.planChangePlanItemInstanceToAvailableOperation(availablePlanItemInstance);
                
                continue;
            }
            
            PlanItemInstance existingPlanItemInstance = null;
            boolean allExistingPlanItemsAreAvailable = true;
            for (PlanItemInstance planItemInstance : planItemInstances) {
                if (PlanItemInstanceState.ACTIVE.equals(planItemInstance.getState()) || PlanItemInstanceState.ENABLED.equals(planItemInstance.getState())) {
                    if (existingPlanItemInstance != null) {
                        throw new FlowableException("multiple active or enabled plan item instances found for plan item definition " + planItemDefinitionMapping.getPlanItemDefinitionId());
                    } else {
                        existingPlanItemInstance = planItemInstance;
                    }
                }
                if (!PlanItemInstanceState.AVAILABLE.equals(planItemInstance.getState())) {
                    allExistingPlanItemsAreAvailable = false;
                }
            }

            if (allExistingPlanItemsAreAvailable) {
                // all existing plan items are available, we can continue without any changes
                continue;
            }
            
            if (existingPlanItemInstance == null) {
                throw new FlowableException("No active or enabled plan item instances found for plan item definition " + planItemDefinitionMapping.getPlanItemDefinitionId());
            }
            

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Complete or disable the duplicate active/enabled instances first so only one remains, then retry the state change
  2. Use movePlanItemInstance(s) targeting specific plan item instance ids rather than definition-level mapping
  3. Query PlanItemInstanceQuery for the planItemDefinitionId to inspect the duplicates and resolve them
  4. Restructure the case model (e.g. stage/milestone boundaries) to avoid multiple concurrent instances

Example fix

// before
changeState.addPlanItemDefinitionMapping(
    new SimplePlanItemDefinitionMapping.Builder().planItemDefinitionId("taskDef").build()); // ambiguous
// after
List<PlanItemInstance> pis = cmmnRuntimeService.createPlanItemInstanceQuery()
    .planItemDefinitionId("taskDef").caseInstanceId(caseId).list();
// move only the specific instance
changeState.addPlanItemInstanceMapping(
    new SimplePlanItemInstanceMapping.Builder().planItemId(pis.get(0).getId()).build());
Defensive patterns

Strategy: validation

Validate before calling

long active = cmmnRuntimeService.createPlanItemInstanceQuery()
    .caseInstanceId(caseInstanceId).planItemDefinitionId(defId)
    .list().stream()
    .filter(p -> PlanItemInstanceState.ACTIVE.equals(p.getState()) || PlanItemInstanceState.ENABLED.equals(p.getState()))
    .count();
if (active > 1) throw new IllegalStateException("Ambiguous move: " + active + " active/enabled instances");

Try / catch

try {
    cmmnRuntimeService.changePlanItemState(caseInstanceId, changeState);
} catch (FlowableException e) {
    if (e.getMessage().startsWith("multiple active or enabled plan item instances")) {
        // fall back to instance-id based move
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling changePlanItemState / changePlanItemInstancesToAvailableState when multiple plan item instances for the same planItemDefinitionId are in ACTIVE or ENABLED state, e.g. multi-instance-like repeated tasks or several enabled tasks of the same definition.

Common situations: Cases where a human task plan item was completed and re-created multiple times leaving several enabled instances; attempting a bulk state move on a plan item that occurs multiple times in the model; user event listeners enabled repeatedly.

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/295ef36134d1997d. Report an issue: GitHub.