flowable/flowable-engine · error · FlowableException
Cannot find plan item '<planItemId>' in case definition with
Error message
Cannot find plan item '<planItemId>' in case definition with id '<caseDefinitionId>'
What it means
Flowable's CMMN dynamic state manager cannot resolve a plan item by its ID within the given case definition model. This is thrown when moving plan item instances to another state (dynamic case management) and the planItemId supplied in the change-state mapping does not exist in the (new) case definition. It protects against silently applying state changes to nonexistent elements.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/AbstractCmmnDynamicStateManager.java:120
protected CmmnEngineConfiguration cmmnEngineConfiguration;
public AbstractCmmnDynamicStateManager(CmmnEngineConfiguration cmmnEngineConfiguration) {
this.cmmnEngineConfiguration = cmmnEngineConfiguration;
}
protected PlanItem resolvePlanItemFromCmmnModelWithDefinitionId(String planItemDefinitionId, String caseDefinitionId) {
CmmnModel cmmnModel = CaseDefinitionUtil.getCmmnModel(caseDefinitionId);
PlanItem planItem = cmmnModel.findPlanItemByPlanItemDefinitionId(planItemDefinitionId);
if (planItem == null) {
throw new FlowableException("Cannot find plan item with definition id '" + planItemDefinitionId + "' in case definition with id '" + caseDefinitionId + "'");
}
return planItem;
}
protected PlanItem resolvePlanItemFromCmmnModel(CmmnModel cmmnModel, String planItemId, String caseDefinitionId) {
PlanItem planItem = cmmnModel.findPlanItem(planItemId);
if (planItem == null) {
throw new FlowableException("Cannot find plan item '" + planItemId + "' in case definition with id '" + caseDefinitionId + "'");
}
return planItem;
}
protected void doMovePlanItemState(CaseInstanceChangeState caseInstanceChangeState, String originalCaseDefinitionId, CommandContext commandContext) {
CaseInstanceEntityManager caseInstanceEntityManager = cmmnEngineConfiguration.getCaseInstanceEntityManager();
CaseInstanceEntity caseInstance = caseInstanceEntityManager.findById(caseInstanceChangeState.getCaseInstanceId());
Map<String, List<PlanItemInstanceEntity>> currentPlanItemInstances = retrievePlanItemInstances(caseInstanceChangeState.getCaseInstanceId());
caseInstanceChangeState.setCurrentPlanItemInstances(currentPlanItemInstances);
executeVerifySatisfiedSentryParts(caseInstanceChangeState, caseInstance, originalCaseDefinitionId, commandContext);
executeTerminatePlanItemInstances(caseInstanceChangeState, caseInstance, commandContext);
executeTerminateNonExistingPlanItemInstancesInTargetCmmnModel(caseInstanceChangeState, commandContext);
setCaseDefinitionIdForPlanItemInstances(currentPlanItemInstances, caseInstanceChangeState.getCaseDefinitionToMigrateTo());View on GitHub (pinned to d6d39ce1c6)
Solutions
- Verify the planItemId exists in the target case definition XML (check the <planItem id="..."> attribute)
- Re-fetch the plan item ids from the current case definition version via the CMMN repository service / model instead of hard-coding them
- Check you are passing the plan item id, not the planItemDefinition or element id
- Redeploy the case definition if the referenced plan item was deleted
Example fix
// before
changeState.addPlanItemDefinitionMapping(
new SimplePlanItemDefinitionMapping.Builder().planItemId("approveTaskOld").build());
// after
PlanItem planItem = cmmnModel.findPlanItem("approveTask"); // must exist in target case definition
changeState.addPlanItemDefinitionMapping(
new SimplePlanItemDefinitionMapping.Builder().planItemId(planItem.getId()).build()); Defensive patterns
Strategy: validation
Validate before calling
PlanItem pi = cmmnModel.findPlanItem(planItemId);
if (pi == null) {
throw new IllegalArgumentException("planItemId " + planItemId + " not present in case definition " + caseDefinitionId);
} Type guard
boolean planItemExists(CmmnModel model, String planItemId) {
return model != null && planItemId != null && model.findPlanItem(planItemId) != null;
} Try / catch
try {
cmmnRuntimeService.changePlanItemState(caseInstanceId, changeState);
} catch (FlowableException e) {
if (e.getMessage().contains("Cannot find plan item")) {
// re-resolve plan item ids from current case definition and retry
} else {
throw e;
}
} Prevention
- Resolve plan item ids from the deployed CMMN model at runtime instead of hard-coding them
- Revalidate ids whenever a new case definition version is deployed
- Use repository service queries to list plan items of the current definition
When it happens
Trigger: Calling CaseInstanceService.changePlanItemState (or movePlanItemInstance(s)ToX) with a planItemDefinitionMapping/changeState whose planItemId is not present in the target case definition's CMMN model, e.g. a stale/typo'd element id or an id from a different case definition version.
Common situations: Hard-coded plan item ids that were renamed or removed after redeploying a new case definition version; copying ids from a different case model; using the plan item definition id instead of the plan item id.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- No case instance found for id ${caseInstanceEntityId}
- DMN decision with key ${externalRef} was not executed. For $
- Cannot find case instance for id ${caseInstanceId}
- Cannot find plan item instance for id ${planItemInstanceId}
- Cannot find task with id ${taskId}
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/173f32ad725b0ff6.
Report an issue: GitHub.