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.TransactionDependentTaskListener What it means
Thrown when a delegateExpression for a transaction-dependent task listener resolves to an object that does not implement TransactionDependentTaskListener. Type check happens in notify() before dispatching the event.
Solutions
- Implement org.activiti.engine.delegate.TransactionDependentTaskListener (notify(DelegateExecution, DelegateTask, Map, Map)) on the bean
- Switch to a regular TaskListener if commit-time-only semantics aren't needed
- Verify the bean name/type at runtime before deployment
Example fix
// before
public class MyBean implements TaskListener {...}
// after
public class MyBean implements TransactionDependentTaskListener {
@Override public void notify(DelegateExecution e, DelegateTask t, 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.TransactionDependentTaskListener)) throw new IllegalStateException(beanName + " must implement TransactionDependentTaskListener");
Type guard
boolean isTxTaskListener(Object o) { return o instanceof org.activiti.engine.delegate.TransactionDependentTaskListener; } Try / catch
try {
taskService.complete(taskId);
} catch (ActivitiIllegalArgumentException e) {
if (e.getMessage().contains("TransactionDependentTaskListener")) {
logger.error("Wrong interface for transaction-dependent task listener", e);
}
} Prevention
- Don't reuse plain TaskListener beans for transaction-dependent listeners
- Add unit tests that resolve the expression and assert the interface
- Keep a naming convention distinguishing tx-dependent listener beans
When it happens
Trigger: activiti:taskListener with transaction-dependent semantics, delegateExpression="${bean}", bean not implementing TransactionDependentTaskListener.
Common situations: Reusing a plain TaskListener or JavaDelegate bean in a transaction-dependent task listener; class refactor dropped the interface; wrong bean wiring in Spring config.
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…
- Exception while invoking TaskListener
- condition expression returns non-Boolean (sequenceFlowId: +…
- condition script returns non-Boolean
AI-assisted analysis of Activiti/Activiti@56435b1a97 (2026-09-09).
Data as JSON: /api/errors/729bd3a9616b2e7e.
Report an issue: GitHub.
Appendix: source
Thrown at activiti-core/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/listener/DelegateExpressionTransactionDependentTaskListener.java:57
String executionId,
Task task,
Map<String, Object> executionVariables,
Map<String, Object> customPropertiesMap
) {
NoExecutionVariableScope scope = new NoExecutionVariableScope();
Object delegate = expression.getValue(scope);
if (delegate instanceof TransactionDependentTaskListener) {
((TransactionDependentTaskListener) delegate).notify(
processInstanceId,
executionId,
task,
executionVariables,
customPropertiesMap
);
} else {
throw new ActivitiIllegalArgumentException(
"Delegate expression " +
expression +
" did not resolve to an implementation of " +
TransactionDependentTaskListener.class
);
}
}
/**
* returns the expression text for this task 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)