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

  1. Ensure the bean referenced by the expression implements OutboundEventSerializer and fix the class if it does not
  2. Verify the expression string and bean name match an actual bean in the application context
  3. 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

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


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/ce26d7f67029500c. Report an issue: GitHub.