flowable/flowable-engine · error · FlowableException
Cannot add an entry criteria
Error message
Cannot add an entry criteria ${entryCriterion.getId()} no matching plan item found to attach it to What it means
Thrown by ConversionHelper.addEntryCriterionToCurrentElement when an <entryCriterion> is encountered during conversion but there is no plan item (e.g. a stage, task, or event listener) currently on the stack to attach it to. Entry criteria must belong to a plan item, so a dangling criterion makes the document invalid.
Solutions
- Move the <entryCriterion> inside the correct <planItem> element so it has a plan item parent.
- Remove the orphaned entry criterion if no plan item should carry it.
- Validate the document against the CMMN XSD which enforces criterion placement inside planItem elements.
Example fix
<!-- before --> <stage id="stage1"> <entryCriterion id="crit1"/> </stage> <!-- after --> <planItem id="task1"> <entryCriterion id="crit1"/> </planItem>
Defensive patterns
Strategy: validation
Validate before calling
// Ensure every entryCriterion is a child of a planItem before conversion
// e.g. XPath check:
// NodeList bad = (NodeList) xpath.evaluate("//entryCriterion[not(parent::planItem)]", doc, XPathConstants.NODESET);
// if (bad.getLength() > 0) throw new IllegalArgumentException("Entry criteria outside planItem"); Try / catch
try {
cmmnModel = converter.convertToCmmnModel(stream, encoding);
} catch (FlowableException e) {
if (e.getMessage().startsWith("Cannot add an entry criteria")) {
// orphaned entry criterion: fix document structure
}
throw e;
} Prevention
- Only place entry/exit criteria inside <planItem> elements.
- Validate against the CMMN XSD which constrains criterion placement.
- Re-check criteria after copy-pasting elements between stages.
When it happens
Trigger: CMMN XML where an <entryCriterion> appears as a child of an element that is not a convertible plan item, or appears where the converter has no current hasEntryCriteria element (e.g. criterion placed directly in a stage instead of inside a planItem).
Common situations: Hand-written or third-party-generated CMMN placing entryCriterion outside <planItem>; copy-paste of criteria into the wrong parent; exporters emitting criteria for deleted plan items.
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
- Could not resolve on part source reference
- A dynamically created plan item can only be injected into a…
- A dynamically created plan item can only be injected into a…
- A 'maxInstanceCount' on a repetition rule with value '0' is…
- a suspended
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/49b418852528623e.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-cmmn-converter/src/main/java/org/flowable/cmmn/converter/ConversionHelper.java:126
HasEntryCriteria hasEntryCriteria = null;
while (hasEntryCriteria == null && iterator.hasPrevious()) {
CmmnElement cmmnElement = iterator.previous();
if (cmmnElement instanceof HasEntryCriteria) {
hasEntryCriteria = (HasEntryCriteria) cmmnElement;
}
}
if (hasEntryCriteria != null) {
if (StringUtils.isEmpty(entryCriterion.getId())) {
// An id is expected by the evaluation algorithm, so setting an internal one if there isn't one
entryCriterion.setId(generateEntryCriterionId(hasEntryCriteria));
}
entryCriterion.setAttachedToRefId(hasEntryCriteria.getId());
hasEntryCriteria.getEntryCriteria().add(entryCriterion);
} else {
throw new FlowableException("Cannot add an entry criteria " + entryCriterion.getId() + " no matching plan item found to attach it to");
}
}
public void addExitCriterion(Criterion exitCriterion) {
exitCriteria.add(exitCriterion);
}
public void addExitCriteriaToCurrentElement(Criterion exitCriterion) {
addExitCriterion(exitCriterion);
ListIterator<CmmnElement> iterator = currentCmmnElements.listIterator(currentCmmnElements.size());
HasExitCriteria hasExitCriteria = null;
while (hasExitCriteria == null && iterator.hasPrevious()) {
CmmnElement cmmnElement = iterator.previous();
if (cmmnElement instanceof HasExitCriteria) {
hasExitCriteria = (HasExitCriteria) cmmnElement;
}
}View on GitHub (pinned to d6d39ce1c6)