Activiti/Activiti · error · ActivitiIllegalArgumentException
Delegate expression did not resolve to an implementation of…
Error message
Delegate expression ${expression} did not resolve to an implementation of class org.activiti.engine.delegate.TransactionDependentExecutionListener What it means
Thrown when a delegateExpression for a transaction-dependent execution listener resolves to an object that does not implement TransactionDependentExecutionListener. Transaction-dependent listeners run only on successful transaction commit, so Activiti validates the resolved type before invoking.
Solutions
- Implement org.activiti.engine.delegate.TransactionDependentExecutionListener (notify(DelegateExecution, FlowElement, Map, Map)) on the target bean
- Use a standard ExecutionListener instead if commit-time semantics are not required
- Confirm the expression resolves to the intended bean at runtime
Example fix
// before
public class MyBean implements ExecutionListener {...}
// used in transaction-dependent listener
// after
public class MyBean implements TransactionDependentExecutionListener {
@Override public void notify(DelegateExecution e, FlowElement fe, Map<String,Object> vars, Map<String,Object> props) {...}
} Defensive patterns
Strategy: type-guard
Validate before calling
Object bean = applicationContext.getBean(beanName); if (!(bean instanceof org.activiti.engine.delegate.TransactionDependentExecutionListener)) throw new IllegalStateException(beanName + " must implement TransactionDependentExecutionListener");
Type guard
boolean isTxExecListener(Object o) { return o instanceof org.activiti.engine.delegate.TransactionDependentExecutionListener; } Try / catch
try {
runtimeService.startProcessInstanceByKey(key);
} catch (ActivitiIllegalArgumentException e) {
if (e.getMessage().contains("TransactionDependentExecutionListener")) {
logger.error("Delegate bean implements wrong interface", e);
}
} Prevention
- Match the interface to the listener kind: plain vs transaction-dependent listeners use different interfaces
- Document bean types next to BPMN references
- Add integration tests that exercise the listener path before deployment
When it happens
Trigger: BPMN <activiti:executionListener event="end"> (transaction-dependent variant) with delegateExpression="${bean}" where bean is not a TransactionDependentExecutionListener.
Common situations: Reusing a plain ExecutionListener or JavaDelegate bean in a transaction-dependent listener slot; refactoring removed the interface; wrong bean name.
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
- Delegate expression did not resolve to an implementation of…
- Delegate expression did not resolve to an implementation of…
- doesn't implement nor
- doesn't implement
- condition expression returns non-Boolean (sequenceFlowId: +…
AI-assisted analysis of Activiti/Activiti@56435b1a97 (2026-09-09).
Data as JSON: /api/errors/34a4f30c56187890.
Report an issue: GitHub.
Appendix: source
Thrown at activiti-core/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/listener/DelegateExpressionTransactionDependentExecutionListener.java:57
String executionId,
FlowElement flowElement,
Map<String, Object> executionVariables,
Map<String, Object> customPropertiesMap
) {
NoExecutionVariableScope scope = new NoExecutionVariableScope();
Object delegate = expression.getValue(scope);
if (delegate instanceof TransactionDependentExecutionListener) {
((TransactionDependentExecutionListener) delegate).notify(
processInstanceId,
executionId,
flowElement,
executionVariables,
customPropertiesMap
);
} else {
throw new ActivitiIllegalArgumentException(
"Delegate expression " +
expression +
" did not resolve to an implementation of " +
TransactionDependentExecutionListener.class
);
}
}
/**
* returns the expression text for this execution listener. Comes in handy if you want to check which listeners you already have.
*/
public String getExpressionText() {
return expression.getExpressionText();
}
}
View on GitHub (pinned to 56435b1a97)