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

  1. Make the bean referenced by the expression implement FlowableEventListener
  2. Fix the expression string so it resolves to the intended listener bean
  3. Re-register the listener if it was removed; verify runtime bean type at startup
  4. 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

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


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)