flowable/flowable-engine · error · FlowableException
DelegateExpression outbound channel model with key ${channel
Error message
DelegateExpression outbound channel model with key ${channelModel.key} resolved channel adapter delegate expression to ${channelAdapter} which is not of type ${OutboundEventChannelAdapter.class} What it means
Thrown during channel registration when a delegate expression for an outbound channel model resolves to an object that does not implement OutboundEventChannelAdapter. The registry must hand events to a correctly typed adapter, so registration fails fast on any other type or null.
Source
Thrown at modules/flowable-event-registry/src/main/java/org/flowable/eventregistry/impl/pipeline/DelegateExpressionOutboundChannelModelProcessor.java:72
public void registerChannelModel(ChannelModel channelModel, String tenantId, EventRegistry eventRegistry, EventRepositoryService eventRepositoryService,
boolean fallbackToDefaultTenant) {
if (channelModel instanceof DelegateExpressionOutboundChannelModel) {
registerChannelModel((DelegateExpressionOutboundChannelModel) channelModel, tenantId);
}
}
protected void registerChannelModel(DelegateExpressionOutboundChannelModel channelModel, String tenantId) {
String delegateExpression = channelModel.getAdapterDelegateExpression();
if (StringUtils.isNotEmpty(delegateExpression)) {
VariableContainerWrapper variableContainer = new VariableContainerWrapper(Collections.emptyMap());
variableContainer.setVariable("tenantId", tenantId);
variableContainer.setTenantId(tenantId);
Object channelAdapter = engineConfiguration.getExpressionManager()
.createExpression(delegateExpression)
.getValue(variableContainer);
if (!(channelAdapter instanceof OutboundEventChannelAdapter)) {
throw new FlowableException(
"DelegateExpression outbound channel model with key " + channelModel.getKey() + " resolved channel adapter delegate expression to "
+ channelAdapter + " which is not of type " + OutboundEventChannelAdapter.class);
}
channelModel.setOutboundEventChannelAdapter(channelAdapter);
}
}
@Override
public void unregisterChannelModel(ChannelModel channelModel, String tenantId, EventRepositoryService eventRepositoryService) {
// Nothing to do
}
public HasExpressionManagerEngineConfiguration getEngineConfiguration() {
return engineConfiguration;
}
public void setEngineConfiguration(HasExpressionManagerEngineConfiguration engineConfiguration) {
this.engineConfiguration = engineConfiguration;View on GitHub (pinned to d6d39ce1c6)
Solutions
- Make the referenced bean implement org.flowable.eventregistry.api.OutboundEventChannelAdapter (implement send(event) plus setEventRegistry/setOutboundChannelModel as required).
- Check the delegate expression string references the correct outbound adapter bean.
- Inspect the resolved object in the message and fix the Spring/CDI wiring.
- For inbound traffic use the inbound processor/channel model instead.
Example fix
// before
channelModel.setChannelAdapterDelegateExpression("${inboundAdapter}"); // resolves to an InboundEventChannelAdapter
// after
channelModel.setChannelAdapterDelegateExpression("${kafkaOutboundAdapter}"); // bean implements OutboundEventChannelAdapter Defensive patterns
Strategy: validation
Validate before calling
Object adapter = applicationContext.getBean(exprName);
if (!(adapter instanceof org.flowable.eventregistry.api.OutboundEventChannelAdapter)) {
throw new IllegalStateException("Bean " + exprName + " is not an OutboundEventChannelAdapter");
} Type guard
boolean isValidOutboundAdapter(Object o) {
return o instanceof org.flowable.eventregistry.api.OutboundEventChannelAdapter;
} Try / catch
try {
eventRegistry.registerChannelModel(channelModel);
} catch (FlowableException e) {
if (e.getMessage().contains("not of type")) {
logger.error("Outbound adapter bean has wrong type: {}", e.getMessage());
}
throw e;
} Prevention
- Declare outbound adapter beans with OutboundEventChannelAdapter as the declared type
- Do not reuse one adapter class for both inbound and outbound channels
- Add an integration test registering all channel models from your deployment resources
When it happens
Trigger: Registering an outbound channel model whose channelAdapterDelegateExpression resolves to a non-OutboundEventChannelAdapter object (wrong bean, wrong class, or null) via the expression manager.
Common situations: Wiring an inbound adapter into an outbound channel; bean class refactored to drop the interface; wrong bean name in the expression; bean factory returning null.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- DelegateExpression inbound channel model with key ${channelM
- Can only use a collection of String elements for referencing
- Unsupported event object type: ${event.getEventObject().getC
- expected expression ${expression} to resolve to ${type} but
- expected expression ${expression} to resolve to ${type} but
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/b783d80a7edf542f.
Report an issue: GitHub.