flowable/flowable-engine · error · FlowableIllegalArgumentException
Delegate expression + expression + did not resolve to an…
Error message
Delegate expression + expression + did not resolve to an implementation of FlowableEventListener
What it means
Thrown by DelegateExpressionFlowableEventListener.onEvent as a FlowableIllegalArgumentException when the configured delegate expression resolves to an object that is not a FlowableEventListener. Because the failure does not originate from a listener itself, failOnException is forced to true so the error cannot be swallowed.
Solutions
- Make the bean referenced by the expression implement FlowableEventListener
- Fix the expression string so it resolves to the intended listener bean
- Re-register the listener if it was removed; verify runtime bean type at startup
- If the resolved instance should be optional, guard the configuration rather than registering a non-listener
Example fix
// before
public class AuditBean { public void audit(FlowableEvent e) { ... } }
// after
public class AuditBean implements FlowableEventListener {
public void onEvent(FlowableEvent event) { audit(event); }
public boolean isFailOnException() { return true; }
} Defensive patterns
Strategy: type-guard
Validate before calling
Object resolved = beanFactory.getBean(expressionString);
if (!(resolved instanceof FlowableEventListener)) {
throw new IllegalStateException("Listener bean must implement FlowableEventListener: " + expressionString);
} Type guard
static boolean isListenerBean(BeanFactory f, String expr) {
try { return f.getBean(expr) instanceof FlowableEventListener; } catch (Exception e) { return false; }
} Try / catch
try { runtimeService.startProcessInstanceByKey(key); }
catch (FlowableIllegalArgumentException e) {
if (e.getMessage().contains("did not resolve to an implementation of " + FlowableEventListener.class.getName())) {
log.error("Listener delegate expression wrong type: {}", e.getMessage());
} else throw e;
} Prevention
- Register only FlowableEventListener implementations via delegate expressions
- Add a startup check that resolves every registered listener expression once
- Verify class-level interface after refactoring listener classes
When it happens
Trigger: An event listener registered via delegate expression ${someBean} resolves to a non-listener object at dispatch time; onEvent then throws instead of delegating ((FlowableEventListener) delegate).onEvent(event).
Common situations: Bean defined with the wrong type in Spring config; expression typo resolving to a different bean; the bean is conditionally of another type (profiles/environments); refactoring a listener class to drop the interface while listener registrations remain.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Class does not implement FlowableEventListener
- doesn't implement FlowableCollectionHandler
- A process instance id is required, but the provided id '" +…
- A process instance id is required, but the provided id
- activatedBefore is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/739ccf80cc0338a7.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/DelegateExpressionFlowableEventListener.java:56
@Override
public void onEvent(FlowableEvent event) {
if (isValidEvent(event)) {
Object delegate = DelegateExpressionUtil.resolveDelegateExpression(expression, new NoExecutionVariableScope());
if (delegate instanceof FlowableEventListener) {
// Cache result of isFailOnException() from delegate-instance
// until next event is received. This prevents us from having to resolve
// the expression twice when an error occurs.
failOnException = ((FlowableEventListener) delegate).isFailOnException();
// Call the delegate
((FlowableEventListener) delegate).onEvent(event);
} else {
// Force failing, since the exception we're about to throw
// cannot be ignored, because it did not originate from the listener itself
failOnException = true;
throw new FlowableIllegalArgumentException("Delegate expression " + expression + " did not resolve to an implementation of " + FlowableEventListener.class.getName());
}
}
}
@Override
public boolean isFailOnException() {
return failOnException;
}
}
View on GitHub (pinned to d6d39ce1c6)