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

  1. Set channelModel.setDeserializerDelegateExpression("${myDeserializer}") referencing a bean implementing InboundEventDeserializer.
  2. Or switch the channel's deserializer type to json/xml if a built-in deserializer suffices.
  3. Validate channel configuration before registration: expression deserializer type must always pair with a non-empty deserializerDelegateExpression.
  4. 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

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


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)