flowable/flowable-engine · error · FlowableException

The default CMMN parse handlers should only support one type

Error message

The default CMMN parse handlers should only support one type, but {parseHandlerClass} supports {supportedTypes}. This is likely a programmatic error

What it means

Thrown while merging CMMN parse handlers at engine initialization: each DefaultCmmnParseHandler must declare exactly one handled type so it can be keyed/replaced by type in the handler map. A handler declaring zero or multiple handled types is a programming bug in a custom/overridden handler.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java:1245

        // Replace any default handler with a custom one (if needed)
        if (getCustomCmmnParseHandlers() != null) {
            Map<Class<?>, CmmnParseHandler> customParseHandlerMap = new HashMap<>();
            for (CmmnParseHandler cmmnParseHandler : getCustomCmmnParseHandlers()) {
                for (Class<?> handledType : cmmnParseHandler.getHandledTypes()) {
                    customParseHandlerMap.put(handledType, cmmnParseHandler);
                }
            }

            for (int i = 0; i < cmmnParseHandlers.size(); i++) {
                // All the default handlers support only one type
                CmmnParseHandler defaultCmmnParseHandler = cmmnParseHandlers.get(i);
                if (defaultCmmnParseHandler.getHandledTypes().size() != 1) {
                    StringBuilder supportedTypes = new StringBuilder();
                    for (Class<?> type : defaultCmmnParseHandler.getHandledTypes()) {
                        supportedTypes.append(" ").append(type.getCanonicalName()).append(" ");
                    }
                    throw new FlowableException("The default CMMN parse handlers should only support one type, but " + defaultCmmnParseHandler.getClass() + " supports " + supportedTypes
                        + ". This is likely a programmatic error");
                } else {
                    Class<?> handledType = defaultCmmnParseHandler.getHandledTypes().iterator().next();
                    if (customParseHandlerMap.containsKey(handledType)) {
                        CmmnParseHandler newBpmnParseHandler = customParseHandlerMap.get(handledType);
                        logger.info("Replacing default CmmnParseHandler {} with {}", defaultCmmnParseHandler.getClass().getName(), newBpmnParseHandler.getClass().getName());
                        cmmnParseHandlers.set(i, newBpmnParseHandler);
                    }
                }
            }
        }

        return cmmnParseHandlers;
    }

    public void initCaseDefinitionDiagramHelper() {
        if (caseDefinitionDiagramHelper == null) {
            caseDefinitionDiagramHelper = new CaseDefinitionDiagramHelper();

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Fix the parse handler so getHandledTypes() returns exactly one Class (split multi-type handlers into one handler per type)
  2. Register the handler via setCustomCmmnParseHandlers (customParseHandlers) instead of replacing defaultCmmnParseHandlers
  3. Revert accidental overrides of default handler classes and re-apply customizations through the supported extension points
  4. Log/inspect each handler's getHandledTypes() at startup to locate the offending class

Example fix

// before
@Override
public List<Class<? extends BaseElement>> getHandledTypes() {
    return List.of(Milestone.class, Stage.class);
}

// after
@Override
public List<Class<? extends BaseElement>> getHandledTypes() {
    return List.of(Milestone.class); // one type per handler
}
Defensive patterns

Strategy: validation

Validate before calling

for (CmmnParseHandler h : cmmnEngineConfiguration.getCmmnParseHandlers()) {
    if (h.getHandledTypes().size() != 1) {
        throw new IllegalStateException(h.getClass() + " must handle exactly one type");
    }
}

Prevention

When it happens

Trigger: customInitCmmnParseHandlers iterates defaultCmmnParseHandlers and encounters a handler whose getHandledTypes().size() != 1 — i.e. a (sub)class in the default handler list was modified or a custom handler was injected into that list returning multiple types.

Common situations: Overriding DefaultCmmnParseHandler.getHandledTypes() to return several Class elements; adding a custom parse handler to cmmnParseHandlers instead of customParseHandlers; upgrading Flowable with an incompatibly overridden handler subclass.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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