{"record":{"id":"3988de57edb5d391","repo":"flowable/flowable-engine","slug":"the-default-cmmn-parse-handlers-should-only-suppor","errorCode":null,"errorMessage":"The default CMMN parse handlers should only support one type, but {parseHandlerClass} supports {supportedTypes}. This is likely a programmatic error","messagePattern":"The default CMMN parse handlers should only support one type, but (.+?) supports (.+?)\\. This is likely a programmatic error","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java","lineNumber":1245,"sourceCode":"\n        // Replace any default handler with a custom one (if needed)\n        if (getCustomCmmnParseHandlers() != null) {\n            Map<Class<?>, CmmnParseHandler> customParseHandlerMap = new HashMap<>();\n            for (CmmnParseHandler cmmnParseHandler : getCustomCmmnParseHandlers()) {\n                for (Class<?> handledType : cmmnParseHandler.getHandledTypes()) {\n                    customParseHandlerMap.put(handledType, cmmnParseHandler);\n                }\n            }\n\n            for (int i = 0; i < cmmnParseHandlers.size(); i++) {\n                // All the default handlers support only one type\n                CmmnParseHandler defaultCmmnParseHandler = cmmnParseHandlers.get(i);\n                if (defaultCmmnParseHandler.getHandledTypes().size() != 1) {\n                    StringBuilder supportedTypes = new StringBuilder();\n                    for (Class<?> type : defaultCmmnParseHandler.getHandledTypes()) {\n                        supportedTypes.append(\" \").append(type.getCanonicalName()).append(\" \");\n                    }\n                    throw new FlowableException(\"The default CMMN parse handlers should only support one type, but \" + defaultCmmnParseHandler.getClass() + \" supports \" + supportedTypes\n                        + \". This is likely a programmatic error\");\n                } else {\n                    Class<?> handledType = defaultCmmnParseHandler.getHandledTypes().iterator().next();\n                    if (customParseHandlerMap.containsKey(handledType)) {\n                        CmmnParseHandler newBpmnParseHandler = customParseHandlerMap.get(handledType);\n                        logger.info(\"Replacing default CmmnParseHandler {} with {}\", defaultCmmnParseHandler.getClass().getName(), newBpmnParseHandler.getClass().getName());\n                        cmmnParseHandlers.set(i, newBpmnParseHandler);\n                    }\n                }\n            }\n        }\n\n        return cmmnParseHandlers;\n    }\n\n    public void initCaseDefinitionDiagramHelper() {\n        if (caseDefinitionDiagramHelper == null) {\n            caseDefinitionDiagramHelper = new CaseDefinitionDiagramHelper();","sourceCodeStart":1227,"sourceCodeEnd":1263,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java#L1227-L1263","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Fix the parse handler so getHandledTypes() returns exactly one Class (split multi-type handlers into one handler per type)","Register the handler via setCustomCmmnParseHandlers (customParseHandlers) instead of replacing defaultCmmnParseHandlers","Revert accidental overrides of default handler classes and re-apply customizations through the supported extension points","Log/inspect each handler's getHandledTypes() at startup to locate the offending class"],"exampleFix":"// before\n@Override\npublic List<Class<? extends BaseElement>> getHandledTypes() {\n    return List.of(Milestone.class, Stage.class);\n}\n\n// after\n@Override\npublic List<Class<? extends BaseElement>> getHandledTypes() {\n    return List.of(Milestone.class); // one type per handler\n}","handlingStrategy":"validation","validationCode":"for (CmmnParseHandler h : cmmnEngineConfiguration.getCmmnParseHandlers()) {\n    if (h.getHandledTypes().size() != 1) {\n        throw new IllegalStateException(h.getClass() + \" must handle exactly one type\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep one parse handler per handled type","Use setCustomCmmnParseHandlers instead of mutating default handler lists","Never override getHandledTypes() to return multiple types","Run engine boot tests after upgrading Flowable with custom handlers"],"tags":["cmmn","parse-handler","initialization","programmatic-error"],"backgroundTag":"internal-invariant-violation","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}