{"record":{"id":"8dd961a0f42cdf58","repo":"flowable/flowable-engine","slug":"the-channel-payload-extractor-expression-for-the-c","errorCode":null,"errorMessage":"The channel payload extractor expression for the channel model with key ${channelModel.key} was empty. The payloadExtractorExpression has to be provided for a channel with an expression deserializer.","messagePattern":"The channel payload extractor expression for the channel model with key (.+?) was empty\\. The payloadExtractorExpression has to be provided for a channel with an expression deserializer\\.","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-event-registry/src/main/java/org/flowable/eventregistry/impl/pipeline/InboundChannelModelProcessor.java","lineNumber":313,"sourceCode":"        } else {\n            throw new FlowableException(\n                \"The channel deserializer expression for the channel model with key \" + channelModel.getKey()\n                    + \" was empty. The deserializerDelegateExpression has to be provided for a channel with an expression deserializer.\");\n        }\n\n        // by default, there is not filtering of events in place\n        InboundEventFilter<?> eventFilter = null;\n        if (StringUtils.isNotEmpty(channelModel.getEventFilterDelegateExpression())) {\n            eventFilter = resolveExpression(channelModel.getEventFilterDelegateExpression(), InboundEventFilter.class);\n        }\n\n        InboundEventTenantDetector<?> eventTenantDetector = null; // By default no multi-tenancy is applied\n\n        InboundEventPayloadExtractor<?> eventPayloadExtractor;\n        if (StringUtils.isNotEmpty(channelModel.getPayloadExtractorDelegateExpression())) {\n            eventPayloadExtractor = resolveExpression(channelModel.getPayloadExtractorDelegateExpression(), InboundEventPayloadExtractor.class);\n        } else {\n            throw new FlowableException(\n                \"The channel payload extractor expression for the channel model with key \" + channelModel.getKey()\n                    + \" was empty. The payloadExtractorExpression has to be provided for a channel with an expression deserializer.\");\n        }\n\n        InboundEventTransformer eventTransformer;\n        if (StringUtils.isEmpty(channelModel.getEventTransformerDelegateExpression())) {\n            eventTransformer = new DefaultInboundEventTransformer();\n        } else {\n            eventTransformer = resolveExpression(channelModel.getEventTransformerDelegateExpression(), InboundEventTransformer.class);\n        }\n\n        InboundEventKeyDetector<?> eventKeyDetector;\n        ChannelEventKeyDetection keyDetection = channelModel.getChannelEventKeyDetection();\n\n        if (keyDetection == null) {\n            throw new FlowableException(\"A channel key detection value is required for inbound channel \" + channelModel.getKey());\n        }\n","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-event-registry/src/main/java/org/flowable/eventregistry/impl/pipeline/InboundChannelModelProcessor.java#L295-L331","documentation":"Thrown when creating an expression-based event processing pipeline: the payloadExtractorDelegateExpression on the channel model is empty. Expression-deserializer channels must supply an InboundEventPayloadExtractor to map the deserialized payload into event payload values, so registration fails.","triggerScenarios":"Registering an inbound channel using the expression deserializer path where channelModel.getPayloadExtractorDelegateExpression() returns null/empty.","commonSituations":"Configuring deserializerDelegateExpression but overlooking payloadExtractorDelegateExpression; channel model UI field left blank; assuming a default payload extractor exists for expression channels (it does not).","solutions":["Set channelModel.setPayloadExtractorDelegateExpression(\"${myPayloadExtractor}\") referencing an InboundEventPayloadExtractor bean.","Implement the extractor to map the deserialized object into EventPayloadInstance values.","Consider the JSON/XML pipelines if you only need standard field-to-payload mapping, which provide built-in extractors.","Add a pre-registration check that all expression-pipeline required fields (deserializerDelegateExpression, payloadExtractorDelegateExpression, eventTransformerDelegateExpression) are non-empty."],"exampleFix":"// before\nchannelModel.setDeserializerDelegateExpression(\"${customDeserializer}\");\n// payload extractor missing\n\n// after\nchannelModel.setDeserializerDelegateExpression(\"${customDeserializer}\");\nchannelModel.setPayloadExtractorDelegateExpression(\"${customPayloadExtractor}\");","handlingStrategy":"validation","validationCode":"if (isNotBlank(channelModel.getDeserializerDelegateExpression())\n        && isBlank(channelModel.getPayloadExtractorDelegateExpression())) {\n    throw new IllegalArgumentException(\"Channel \" + channelModel.getKey()\n        + \" needs payloadExtractorDelegateExpression for expression deserializer\");\n}","typeGuard":"null","tryCatchPattern":"try {\n    eventRegistry.registerChannelModel(channelModel);\n} catch (FlowableException e) {\n    if (e.getMessage().contains(\"payload extractor expression\")) {\n        logger.error(\"Set payloadExtractorDelegateExpression on channel {}\", channelModel.getKey());\n    }\n    throw e;\n}","preventionTips":["Configure deserializer, payload extractor (and event transformer) delegate expressions together for expression channels","Implement and test InboundEventPayloadExtractor beans before wiring them into channels","Use the JSON/XML pipelines when standard payload mapping suffices"],"tags":["flowable","event-registry","missing-config","payload-extractor"],"backgroundTag":"missing-required-config-field","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"}