flowable/flowable-engine · error · FlowableException
expected expression ${expression} to resolve to ${type} but
Error message
expected expression ${expression} to resolve to ${type} but it did not. Resolved value is ${value} What it means
OutboundChannelModelProcessor.resolveExpression evaluates a delegate expression and checks that the resulting object is an instance of the requested type (typically OutboundEventSerializer). If the expression resolves to null or an object of a different type, this FlowableException is thrown rather than performing an unsafe cast.
Source
Thrown at modules/flowable-event-registry/src/main/java/org/flowable/eventregistry/impl/pipeline/OutboundChannelModelProcessor.java:110
}
if (eventProcessingPipeline != null) {
outboundChannelModel.setOutboundEventProcessingPipeline(eventProcessingPipeline);
}
}
}
protected <T> T resolveExpression(String expression, Class<T> type) {
Object value = CommandContextUtil.getEventRegistryConfiguration().getExpressionManager()
.createExpression(expression)
.getValue(new VariableContainerWrapper(Collections.emptyMap()));
if (type.isInstance(value)) {
return type.cast(value);
}
throw new FlowableException("expected expression " + expression + " to resolve to " + type + " but it did not. Resolved value is " + value);
}
@Override
public void unregisterChannelModel(ChannelModel channelModel, String tenantId, EventRepositoryService eventRepositoryService) {
// nothing to do
}
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Ensure the bean referenced by the expression implements OutboundEventSerializer and fix the class if it does not
- Verify the expression string and bean name match an actual bean in the application context
- If the expression returns null, fix bean availability (component scan, conditional bean profiles) so it is created before channel registration
Example fix
// before
@Bean
public JsonSerializer jsonSerializer() { ... } // not an OutboundEventSerializer
// after
@Bean
public OutboundEventSerializer jsonSerializer() { return new JacksonOutboundEventSerializer(objectMapper); } Defensive patterns
Strategy: validation
Validate before calling
Object bean = applicationContext.getBean(serializerBeanName);
if (!(bean instanceof OutboundEventSerializer)) {
throw new IllegalArgumentException(serializerBeanName + " must implement OutboundEventSerializer, got " + bean.getClass());
} Type guard
boolean isSerializer = obj instanceof OutboundEventSerializer;
Try / catch
try {
registerChannelModel(...);
} catch (FlowableException e) {
if (e.getMessage().startsWith("expected expression")) {
// verify serializer bean type/name
} else { throw e; }
} Prevention
- Declare @Bean methods with OutboundEventSerializer as the return type
- Avoid naming collisions between inbound and outbound serializer beans
- Validate expressions resolve at startup with a health check
When it happens
Trigger: Outbound channel registration (registerChannelModel) or outboundEventSerializer resolution where a serializerDelegateExpression (or similar) resolves to a bean that is not an OutboundEventSerializer, or the expression evaluates to null.
Common situations: delegateExpression pointing at a bean of the wrong type (e.g. an InboundEventSerializer); bean name typo resolving to null; bean defined but not registered in the Spring context used by the event registry; custom serializer missing the interface.
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
- expected expression ${expression} to resolve to ${type} but
- decisionTableReferenceKey expression does not resolve to a s
- Skip expression does not resolve to a boolean: " + skipExpre
- Unable to resolve formFieldValidationExpression to boolean v
- DelegateExpression inbound channel model with key ${channelM
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/ce26d7f67029500c.
Report an issue: GitHub.