{"record":{"id":"903f49f8306d69f0","repo":"flowable/flowable-engine","slug":"cannot-find-a-planitemdefinitionexporter-for-pla","errorCode":null,"errorMessage":"Cannot find a PlanItemDefinitionExporter for '{planItemDefinitionClass}'","messagePattern":"Cannot find a PlanItemDefinitionExporter for '(.+?)'","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-converter/src/main/java/org/flowable/cmmn/converter/export/PlanItemDefinitionExport.java","lineNumber":60,"sourceCode":"        addPlanItemDefinitionExport(new ExternalWorkerServiceTaskExport());\n        addPlanItemDefinitionExport(new MilestoneExport());\n        addPlanItemDefinitionExport(new GenericEventListenerExport());\n        addPlanItemDefinitionExport(new SignalEventListenerExport());\n        addPlanItemDefinitionExport(new IntentEventListenerExport());\n        addPlanItemDefinitionExport(new ReactivationEventListenerExport());\n        addPlanItemDefinitionExport(new TimerEventListenerExport());\n        addPlanItemDefinitionExport(new UserEventListenerExport());\n        addPlanItemDefinitionExport(new VariableEventListenerExport());\n    }\n\n    public static void addPlanItemDefinitionExport(AbstractPlanItemDefinitionExport exporter) {\n        planItemDefinitionExporters.put(exporter.getExportablePlanItemDefinitionClass().getCanonicalName(), exporter);\n    }\n\n    public static void writePlanItemDefinition(CmmnModel model, PlanItemDefinition planItemDefinition, XMLStreamWriter xtw, CmmnXmlConverterOptions options) throws Exception {\n        AbstractPlanItemDefinitionExport exporter = determineExporter(planItemDefinition);\n        if (exporter == null) {\n            throw new FlowableException(\"Cannot find a PlanItemDefinitionExporter for '\" + planItemDefinition.getClass().getCanonicalName() + \"'\");\n        }\n        exporter.writePlanItemDefinition(model, planItemDefinition, xtw, options);\n    }\n\n    protected static AbstractPlanItemDefinitionExport determineExporter(PlanItemDefinition planItemDefinition) {\n\n        AbstractPlanItemDefinitionExport exporter = null;\n        Class currentPlanItemDefinitionClass = planItemDefinition.getClass();\n\n        while (exporter == null && !currentPlanItemDefinitionClass.equals(PlanItemDefinition.class)) {\n            String exporterType = currentPlanItemDefinitionClass.getCanonicalName();\n            exporter = planItemDefinitionExporters.get(exporterType);\n\n            currentPlanItemDefinitionClass = currentPlanItemDefinitionClass.getSuperclass(); // loop will stop once PlanItemDefinition is reached, so only child hierarchies will be checked\n        }\n\n        return exporter;\n    }","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-converter/src/main/java/org/flowable/cmmn/converter/export/PlanItemDefinitionExport.java#L42-L78","documentation":"During CMMN model export, each PlanItemDefinition requires a registered exporter (AbstractPlanItemDefinitionExport) keyed by the definition's canonical class name. If no exporter matches the plan item definition's class, Flowable throws this FlowableException.","triggerScenarios":"Calling PlanItemDefinitionExport.writePlanItemDefinition (or converting a model to XML) with a custom/unregistered PlanItemDefinition subclass that was never registered via the register mechanism, or with a definition type not supported by the installed converters.","commonSituations":"Custom plan item definitions added via extension API without registering a matching exporter; classpath mixing Flowable versions so built-in exporters are missing; deserialized models with new definition types exported by an older converter.","solutions":["Register an exporter for the custom class via the exporter registration method (registerPlanItemDefinitionExporter / put in planItemDefinitionExporters).","Ensure your custom PlanItemDefinition subclasses a supported built-in type (e.g. Task, UserEventListener).","Align Flowable dependency versions (converter vs engine) so all built-in exporters are present.","If you don't need the element exported, remove it from the CmmnModel before conversion."],"exampleFix":"// before\nmodel.addPlanItemDefinition(new MyCustomTask()); // no exporter registered\n// after\nFlowableCmmnXmlConverter.registerPlanItemDefinitionExporter(\"com.acme.MyCustomTask\", new MyCustomTaskExport());","handlingStrategy":"validation","validationCode":"public static boolean hasExporter(PlanItemDefinition pid) {\n    return AbstractPlanItemDefinitionExportRegistry != null\n        && org.flowable.cmmn.converter.export.PlanItemDefinitionExport.class != null; // check via determineExporter reflection\n}\n// simpler: verify class is a known built-in type\npublic static boolean isSupported(PlanItemDefinition pid) {\n    return pid instanceof org.flowable.cmmn.model.Task\n        || pid instanceof org.flowable.cmmn.model.EventListener\n        || pid instanceof org.flowable.cmmn.model.Stage\n        || pid instanceof org.flowable.cmmn.model.Milestone;\n}","typeGuard":null,"tryCatchPattern":"try {\n    CmmnXMLConverter.convertToXMLDocument(model);\n} catch (FlowableException e) {\n    if (e.getMessage().startsWith(\"Cannot find a PlanItemDefinitionExporter\")) {\n        logger.error(\"Register an exporter for the custom plan item definition before export\", e);\n    }\n    throw e;\n}","preventionTips":["Always register a custom exporter when adding custom PlanItemDefinition subclasses","Keep flowable-engine and flowable-cmmn-converter versions aligned","Prefer subclassing supported built-in definition types"],"tags":["cmmn","export","extension-api"],"backgroundTag":"missing-dependency","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}