flowable/flowable-engine · error · FlowableIllegalArgumentException
<delegateClassName> doesn't implement TransactionDependentEx
Error message
<delegateClassName> doesn't implement TransactionDependentExecutionListener
What it means
Flowable's ClassDelegate instantiates the class configured for a transaction-dependent execution listener and checks that it implements TransactionDependentExecutionListener. If the instantiated object does not implement that interface, a FlowableIllegalArgumentException is thrown naming the class and the missing interface. The library enforces this contract because it must invoke the listener's transaction-aware notification methods during commit/rollback phases.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java:147
CommandContextUtil.getProcessEngineConfiguration().getDelegateInterceptor().handleInvocation(new TaskListenerInvocation(taskListenerInstance, delegateTask));
}
@Override
public void notify(String processInstanceId, String executionId, Task task, Map<String, Object> executionVariables, Map<String, Object> customPropertiesMap) {
TransactionDependentTaskListener transactionDependentTaskListenerInstance = getTransactionDependentTaskListenerInstance();
transactionDependentTaskListenerInstance.notify(processInstanceId, executionId, task, executionVariables, customPropertiesMap);
}
protected ExecutionListener getExecutionListenerInstance() {
return new DelegateExecutionListener(instantiateDelegate(className, fieldDeclarations));
}
protected TransactionDependentExecutionListener getTransactionDependentExecutionListenerInstance() {
Object delegateInstance = instantiateDelegate(className, fieldDeclarations);
if (delegateInstance instanceof TransactionDependentExecutionListener) {
return (TransactionDependentExecutionListener) delegateInstance;
} else {
throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + " doesn't implement " + TransactionDependentExecutionListener.class);
}
}
protected CustomPropertiesResolver getCustomPropertiesResolverInstance() {
Object delegateInstance = instantiateDelegate(className, fieldDeclarations);
if (delegateInstance instanceof CustomPropertiesResolver) {
return (CustomPropertiesResolver) delegateInstance;
} else {
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);View on GitHub (pinned to d6d39ce1c6)
Solutions
- Make the configured class implement org.flowable.engine.delegate.TransactionDependentExecutionListener (notify method taking TransactionDependentExecutionListenerExecution).
- Verify the class name in the BPMN XML matches the fully qualified name of the intended implementation.
- Rebuild/redeploy so the deployed classpath contains the compiled implementation of the interface.
- If you meant a plain listener, move the class to the flowable:executionListener attribute instead.
Example fix
// before
public class MyListener implements ExecutionListener { ... }
<!-- flowable:transactionDependentExecutionListener class="com.acme.MyListener" -->
// after
public class MyListener implements TransactionDependentExecutionListener {
@Override
public void notify(TransactionDependentExecutionListenerExecution execution) { ... }
} Defensive patterns
Strategy: validation
Validate before calling
Class<?> c = Class.forName("com.acme.MyListener");
if (!TransactionDependentExecutionListener.class.isAssignableFrom(c))
throw new IllegalStateException("Class must implement TransactionDependentExecutionListener"); Type guard
boolean isValidListener(Object o) { return o instanceof TransactionDependentExecutionListener; } Try / catch
try {
runtimeService.startProcessInstanceByKey("key");
} catch (FlowableIllegalArgumentException e) {
if (e.getMessage().contains("TransactionDependentExecutionListener")) { /* fix deployment/class */ }
throw e;
} Prevention
- Always implement the exact interface named in the error message with the Flowable package prefix.
- Unit-test delegate instantiation before deploying the process.
- Keep class attributes in BPMN as constants shared with the class definitions.
- Run a smoke deployment test in CI that resolves all delegates.
When it happens
Trigger: A BPMN element (e.g. service task or user task) is configured with flowable:transactionDependentExecutionListener class='<delegateClassName>', and the referenced class (or a field-declaration instantiation of it) does not implement org.flowable.engine.delegate.TransactionDependentExecutionListener.
Common situations: Copy-pasting an ordinary ExecutionListener/JavaDelegate class into a transactionDependentExecutionListener attribute; renaming or refactoring the class so it no longer implements the interface; pointing the XML at the wrong class name; classpath collisions loading a stale version of the class.
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 CustomPropertiesResolv
- <delegateClassName> doesn't implement TaskListener
- <delegateClassName> doesn't implement TransactionDependentTa
- <delegateClassName> doesn't implement JavaDelegate, FutureJa
- <delegateClassName> doesn't implement FlowableCollectionHand
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/8003321c0851ef6a.
Report an issue: GitHub.