flowable/flowable-engine · error · FlowableException

Could not resolve on part source reference

Error message

Could not resolve on part source reference ${onPart.getSourceRef()} of sentry ${sentry.getId()}

What it means

Thrown by CmmnXmlConverter.processSentries when a sentry's onPart references a sourceRef that does not match any plan item in the plan model (searched downwards into nested plan fragments). CMMN sentries react to plan items, so an unresolvable sourceRef means the CMMN XML is inconsistent and conversion aborts.

Solutions

  1. Fix the sourceRef attribute of the planItemOnPart so it matches the id of an existing <planItem> in the same plan fragment or a nested one.
  2. Remove or restructure the sentry if its source plan item was intentionally deleted.
  3. Validate the CMMN XML against the XSD and cross-check all sourceRef/targetRef ids before deployment.

Example fix

<!-- before -->
<sentry id="sentry1">
  <planItemOnPart sourceRef="oldPlanItemId"/>
</sentry>
<!-- after -->
<sentry id="sentry1">
  <planItemOnPart sourceRef="existingPlanItemId"/>
</sentry>
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate all sentry on-part sourceRefs before conversion
for (Sentry sentry : planFragment.getSentries()) {
    for (SentryOnPart onPart : sentry.getOnParts()) {
        if (planModelStage.findPlanItemInPlanFragmentOrDownwards(onPart.getSourceRef()) == null) {
            throw new IllegalArgumentException("Unresolved onPart sourceRef: " + onPart.getSourceRef());
        }
    }
}

Try / catch

try {
    cmmnModel = converter.convertToCmmnModel(inputStream, encoding);
} catch (FlowableException e) {
    if (e.getMessage().contains("Could not resolve on part source reference")) {
        // flag the offending CMMN document for authoring-time validation
    }
    throw e;
}

Prevention

When it happens

Trigger: Parsing a CMMN XML file whose <sentry><planItemOnPart sourceRef="X"> points to a plan item id that does not exist, was renamed, is defined in a different case/plan fragment, or is misspelled.

Common situations: Hand-edited or externally generated CMMN XML; refactoring plan item ids without updating sentry on-parts; copy-pasting sentries between cases or stages where the referenced plan item is not in the same plan model hierarchy; tools exporting partial plan models.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-cmmn-converter/src/main/java/org/flowable/cmmn/converter/CmmnXmlConverter.java:639

        for (Criterion exitCriterion : hasExitCriteria.getExitCriteria()) {
            Sentry sentry = exitCriterion.getParent().findSentry(exitCriterion.getSentryRef());
            if (sentry != null) {
                exitCriterion.setSentry(sentry);
            } else {
                throw new FlowableException("No sentry found for reference "
                        + exitCriterion.getSentryRef() + " of exit criterion " + exitCriterion.getId());
            }
        }
    }

    protected void processSentries(Stage planModelStage, PlanFragment planFragment) {
        for (Sentry sentry : planFragment.getSentries()) {
            for (SentryOnPart onPart : sentry.getOnParts()) {
                PlanItem planItem = planModelStage.findPlanItemInPlanFragmentOrDownwards(onPart.getSourceRef());
                if (planItem != null) {
                    onPart.setSource(planItem);
                } else {
                    throw new FlowableException("Could not resolve on part source reference "
                            + onPart.getSourceRef() + " of sentry " + sentry.getId());
                }
            }
        }

        for (PlanItem planItem : planFragment.getPlanItems()) {
            if (planItem.getPlanItemDefinition() instanceof PlanFragment) {
                processSentries(planModelStage, (PlanFragment) planItem.getPlanItemDefinition());
            }
        }
    }

    protected void ensureIds(List<? extends BaseElement> elements, String idPrefix) {
        Map<String, BaseElement> elementsWithId = new HashMap<>();
        Set<BaseElement> baseElementsWithoutId = new HashSet<>();
        for (BaseElement baseElement : elements) {
            if (baseElement.getId() != null) {
                elementsWithId.put(baseElement.getId(), baseElement);

View on GitHub (pinned to d6d39ce1c6)