flowable/flowable-engine · error · FlowableException
The channel deserializer expression for the channel model…
Error message
The channel deserializer expression for the channel model with key ${channelModel.key} was empty. The deserializerDelegateExpression has to be provided for a channel with an expression deserializer. What it means
Thrown when creating an expression-based event processing pipeline: the channel model is configured for a delegate-expression deserializer, but getDeserializerDelegateExpression() is empty. The pipeline has no way to deserialize raw payloads without it.
Solutions
- Set channelModel.setDeserializerDelegateExpression("${myDeserializer}") referencing a bean implementing InboundEventDeserializer.
- Or switch the channel's deserializer type to json/xml if a built-in deserializer suffices.
- Validate channel configuration before registration: expression deserializer type must always pair with a non-empty deserializerDelegateExpression.
- Deploy the referenced InboundEventDeserializer bean so the expression also resolves.
Example fix
// before
channelModel.setDeserializerType("expression"); // but no delegate expression set
// after
channelModel.setDeserializerType("expression");
channelModel.setDeserializerDelegateExpression("${customEventDeserializer}"); Defensive patterns
Strategy: validation
Validate before calling
if ("expression".equals(channelModel.getDeserializerType())
&& isBlank(channelModel.getDeserializerDelegateExpression())) {
throw new IllegalArgumentException("Channel " + channelModel.getKey()
+ " uses expression deserializer but deserializerDelegateExpression is empty");
} Type guard
null
Try / catch
try {
eventRegistry.registerChannelModel(channelModel);
} catch (FlowableException e) {
if (e.getMessage().contains("deserializer expression")) {
logger.error("Set deserializerDelegateExpression on channel {}", channelModel.getKey());
}
throw e;
} Prevention
- Always pair deserializerType=expression with a deserializerDelegateExpression
- Ensure the referenced InboundEventDeserializer bean is deployed before registration
- Prefer built-in json/xml deserializers when no custom logic is needed
When it happens
Trigger: Registering an inbound channel whose deserializer type is 'expression' (createExpressionEventProcessingPipeline path) while channelModel.getDeserializerDelegateExpression() returns null/empty.
Common situations: Selecting deserializer type expression in the channel model editor but forgetting to fill deserializerDelegateExpression; copying a JSON/XML channel definition and switching the deserializer type without adding the expression; programmatic construction missing setDeserializerDelegateExpression.
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 json key detection value was not found for the…
- The channel json tenant detection value was not found for…
- The channel payload extractor expression for the channel…
- 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/f6c603b321c9781a.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-event-registry/src/main/java/org/flowable/eventregistry/impl/pipeline/InboundChannelModelProcessor.java:296
configurationPayloadExtractor,
channelPayloadExtractor
));
}
return new CompositePayloadExtractor<>(Arrays.asList(
modelEventPayloadExtractor,
configurationPayloadExtractor
));
}
protected InboundEventProcessingPipeline createExpressionEventProcessingPipeline(InboundChannelModel channelModel,
EventRepositoryService eventRepositoryService) {
InboundEventDeserializer<?> eventDeserializer;
if (StringUtils.isNotEmpty(channelModel.getDeserializerDelegateExpression())) {
eventDeserializer = resolveExpression(channelModel.getDeserializerDelegateExpression(), InboundEventDeserializer.class);
} 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()View on GitHub (pinned to d6d39ce1c6)