flowable/flowable-engine · error · FlowableException
The channel payload extractor expression for the channel…
Error message
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. What it means
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.
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.
Example fix
// before
channelModel.setDeserializerDelegateExpression("${customDeserializer}");
// payload extractor missing
// after
channelModel.setDeserializerDelegateExpression("${customDeserializer}");
channelModel.setPayloadExtractorDelegateExpression("${customPayloadExtractor}"); Defensive patterns
Strategy: validation
Validate before calling
if (isNotBlank(channelModel.getDeserializerDelegateExpression())
&& isBlank(channelModel.getPayloadExtractorDelegateExpression())) {
throw new IllegalArgumentException("Channel " + channelModel.getKey()
+ " needs payloadExtractorDelegateExpression for expression deserializer");
} Type guard
null
Try / catch
try {
eventRegistry.registerChannelModel(channelModel);
} catch (FlowableException e) {
if (e.getMessage().contains("payload extractor expression")) {
logger.error("Set payloadExtractorDelegateExpression on channel {}", channelModel.getKey());
}
throw e;
} Prevention
- 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
When it happens
Trigger: Registering an inbound channel using the expression deserializer path where channelModel.getPayloadExtractorDelegateExpression() returns null/empty.
Common situations: Configuring deserializerDelegateExpression but overlooking payloadExtractorDelegateExpression; channel model UI field left blank; assuming a default payload extractor exists for expression channels (it does not).
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- A channel key detection value is required for inbound…
- The channel deserializer expression for the channel model…
- The channel json key detection value was not found for the…
- The channel json tenant detection value was not found for…
- The channel xml key detection value was not found for the…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/8dd961a0f42cdf58.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-event-registry/src/main/java/org/flowable/eventregistry/impl/pipeline/InboundChannelModelProcessor.java:313
} else {
throw new FlowableException(
"The channel deserializer expression for the channel model with key " + channelModel.getKey()
+ " was empty. The deserializerDelegateExpression has to be provided for a channel with an expression deserializer.");
}
// by default, there is not filtering of events in place
InboundEventFilter<?> eventFilter = null;
if (StringUtils.isNotEmpty(channelModel.getEventFilterDelegateExpression())) {
eventFilter = resolveExpression(channelModel.getEventFilterDelegateExpression(), InboundEventFilter.class);
}
InboundEventTenantDetector<?> eventTenantDetector = null; // By default no multi-tenancy is applied
InboundEventPayloadExtractor<?> eventPayloadExtractor;
if (StringUtils.isNotEmpty(channelModel.getPayloadExtractorDelegateExpression())) {
eventPayloadExtractor = resolveExpression(channelModel.getPayloadExtractorDelegateExpression(), InboundEventPayloadExtractor.class);
} else {
throw new FlowableException(
"The channel payload extractor expression for the channel model with key " + channelModel.getKey()
+ " was empty. The payloadExtractorExpression has to be provided for a channel with an expression deserializer.");
}
InboundEventTransformer eventTransformer;
if (StringUtils.isEmpty(channelModel.getEventTransformerDelegateExpression())) {
eventTransformer = new DefaultInboundEventTransformer();
} else {
eventTransformer = resolveExpression(channelModel.getEventTransformerDelegateExpression(), InboundEventTransformer.class);
}
InboundEventKeyDetector<?> eventKeyDetector;
ChannelEventKeyDetection keyDetection = channelModel.getChannelEventKeyDetection();
if (keyDetection == null) {
throw new FlowableException("A channel key detection value is required for inbound channel " + channelModel.getKey());
}
View on GitHub (pinned to d6d39ce1c6)