flowable/flowable-engine · error · FlowableIllegalArgumentException
<delegateClassName> doesn't implement TransactionDependentTa
Error message
<delegateClassName> doesn't implement TransactionDependentTaskListener
What it means
ClassDelegate instantiates the class configured as a transaction-dependent task listener and casts it to TransactionDependentTaskListener. If the instance does not implement that interface, a FlowableIllegalArgumentException naming the class and expected interface is thrown. Flowable needs this interface to invoke listeners during the transaction commit/rollback phases of a task.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java:174
throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + " doesn't implement " + CustomPropertiesResolver.class);
}
}
protected TaskListener getTaskListenerInstance() {
Object delegateInstance = instantiateDelegate(className, fieldDeclarations);
if (delegateInstance instanceof TaskListener) {
return (TaskListener) delegateInstance;
} else {
throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + " doesn't implement " + TaskListener.class);
}
}
protected TransactionDependentTaskListener getTransactionDependentTaskListenerInstance() {
Object delegateInstance = instantiateDelegate(className, fieldDeclarations);
if (delegateInstance instanceof TransactionDependentTaskListener) {
return (TransactionDependentTaskListener) delegateInstance;
} else {
throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + " doesn't implement " + TransactionDependentTaskListener.class);
}
}
// Activity Behavior
@Override
public void execute(DelegateExecution execution) {
if (CommandContextUtil.getProcessEngineConfiguration().isEnableProcessDefinitionInfoCache()) {
ObjectNode taskElementProperties = BpmnOverrideContext.getBpmnOverrideElementProperties(serviceTaskId, execution.getProcessDefinitionId());
if (taskElementProperties != null && taskElementProperties.has(DynamicBpmnConstants.SERVICE_TASK_CLASS_NAME)) {
String overrideClassName = taskElementProperties.get(DynamicBpmnConstants.SERVICE_TASK_CLASS_NAME).asString();
if (StringUtils.isNotEmpty(overrideClassName) && !overrideClassName.equals(className)) {
className = overrideClassName;
activityBehaviorInstance = null;
}
}
}
if (activityBehaviorInstance == null) {View on GitHub (pinned to d6d39ce1c6)
Solutions
- Make the configured class implement TransactionDependentTaskListener (getListenerEvents + notify).
- Check the XML class attribute matches the intended fully qualified class.
- Redeploy so the deployed artifact contains the implementation.
- Use a regular flowable:taskListener if transaction-phase notification is not required.
Example fix
// before
public class MyListener implements TaskListener { ... }
<!-- flowable:transactionDependentTaskListener class="com.acme.MyListener" -->
// after
public class MyListener implements TransactionDependentTaskListener {
@Override public Set<String> getListenerEvents() { return Collections.singleton(EVENTNAME_COMMITTED); }
@Override public void notify(TransactionDependentTaskListenerExecution execution, List<TaskInfo> tasks) { ... }
} Defensive patterns
Strategy: validation
Validate before calling
Class<?> c = Class.forName(listenerClass);
if (!TransactionDependentTaskListener.class.isAssignableFrom(c))
throw new IllegalStateException("Must implement TransactionDependentTaskListener"); Type guard
boolean isValid(Object o) { return o instanceof TransactionDependentTaskListener; } Try / catch
try {
taskService.complete(taskId);
} catch (FlowableIllegalArgumentException e) {
if (e.getMessage().contains("TransactionDependentTaskListener")) { /* fix class */ }
throw e;
} Prevention
- Use transactionDependentTaskListener only with the matching interface.
- Keep listener events set (getListenerEvents) implemented alongside notify.
- Validate all listener classes at deployment time.
When it happens
Trigger: A user task declares flowable:transactionDependentTaskListener class='<delegateClassName>' and the class does not implement org.flowable.engine.delegate.TransactionDependentTaskListener.
Common situations: Reusing a plain TaskListener class under the transactionDependent variant; refactoring dropped the interface; wrong class name in the BPMN XML; stale deployed jar missing the implementation.
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
- <delegateClassName> doesn't implement TaskListener
- Delegate expression ${expression} did not resolve to an impl
- <delegateClassName> doesn't implement TransactionDependentEx
- <delegateClassName> doesn't implement CustomPropertiesResolv
- <delegateClassName> doesn't implement JavaDelegate, FutureJa
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/4bb0499788002ed4.
Report an issue: GitHub.