{"record":{"id":"f6c603b321c9781a","repo":"flowable/flowable-engine","slug":"the-channel-deserializer-expression-for-the-channe","errorCode":null,"errorMessage":"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.","messagePattern":"The channel deserializer expression for the channel model with key (.+?) was empty\\. The deserializerDelegateExpression 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":296,"sourceCode":"                    configurationPayloadExtractor,\n                    channelPayloadExtractor\n            ));\n        }\n\n        return new CompositePayloadExtractor<>(Arrays.asList(\n                modelEventPayloadExtractor,\n                configurationPayloadExtractor\n        ));\n    }\n\n    protected InboundEventProcessingPipeline createExpressionEventProcessingPipeline(InboundChannelModel channelModel,\n            EventRepositoryService eventRepositoryService) {\n        \n        InboundEventDeserializer<?> eventDeserializer;\n        if (StringUtils.isNotEmpty(channelModel.getDeserializerDelegateExpression())) {\n            eventDeserializer = resolveExpression(channelModel.getDeserializerDelegateExpression(), InboundEventDeserializer.class);\n        } 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()","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-event-registry/src/main/java/org/flowable/eventregistry/impl/pipeline/InboundChannelModelProcessor.java#L278-L314","documentation":"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.","triggerScenarios":"Registering an inbound channel whose deserializer type is 'expression' (createExpressionEventProcessingPipeline path) while channelModel.getDeserializerDelegateExpression() returns null/empty.","commonSituations":"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.","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."],"exampleFix":"// before\nchannelModel.setDeserializerType(\"expression\"); // but no delegate expression set\n\n// after\nchannelModel.setDeserializerType(\"expression\");\nchannelModel.setDeserializerDelegateExpression(\"${customEventDeserializer}\");","handlingStrategy":"validation","validationCode":"if (\"expression\".equals(channelModel.getDeserializerType())\n        && isBlank(channelModel.getDeserializerDelegateExpression())) {\n    throw new IllegalArgumentException(\"Channel \" + channelModel.getKey()\n        + \" uses expression deserializer but deserializerDelegateExpression is empty\");\n}","typeGuard":"null","tryCatchPattern":"try {\n    eventRegistry.registerChannelModel(channelModel);\n} catch (FlowableException e) {\n    if (e.getMessage().contains(\"deserializer expression\")) {\n        logger.error(\"Set deserializerDelegateExpression on channel {}\", channelModel.getKey());\n    }\n    throw e;\n}","preventionTips":["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"],"tags":["flowable","event-registry","missing-config","deserializer"],"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"}