flowable/flowable-engine · error · ActivitiException
Exception while invoking TaskListener
Error message
Exception while invoking TaskListener: ${e.getMessage()} What it means
Thrown as ActivitiException from DelegateExpressionTaskListener.notify when the resolved delegate is a TaskListener but invoking it through the configured DelegateInterceptor (TaskListenerInvocation) throws an exception. The original exception's message is embedded and the cause is attached.
Solutions
- Read the wrapped cause (e.getCause()) — the message here only repeats the inner exception's message.
- Fix the exception inside the TaskListener implementation itself (null checks, error handling around external calls).
- Check the delegate interceptor configuration for custom wrapping that might throw.
- Add logging inside the listener to pinpoint the failing statement.
- If the failure is environmental (DB, network), make the listener retry or degrade gracefully instead of throwing.
Example fix
// before: listener body can NPE
public void notify(DelegateTask task) { task.getVariable("cfg").toString(); }
// after: guard
public void notify(DelegateTask task) {
Object cfg = task.getVariable("cfg");
if (cfg != null) { cfg.toString(); }
} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight: resolve and dry-run the delegate where possible
Object delegate = applicationContext.getBean("myTaskListener");
if (!(delegate instanceof TaskListener)) {
throw new IllegalStateException("myTaskListener is not a TaskListener");
} Try / catch
try {
taskService.complete(taskId);
} catch (ActivitiException e) {
if (e.getMessage().startsWith("Exception while invoking TaskListener")) {
Throwable root = e;
while (root.getCause() != null) root = root.getCause();
logger.error("TaskListener failed: ", root);
}
throw e;
} Prevention
- Unwrap getCause() chains — this error's message is only the inner exception's message.
- Keep TaskListener bodies defensive: null-check variables and wrap external calls.
- Avoid heavyweight logic (network, transactions) inside task listeners, or handle failures locally.
- Unit-test listeners with a DelegateTask mock before process deployment.
When it happens
Trigger: A <activiti:taskListener event="..." delegateExpression="${bean}"/> resolves to a valid TaskListener, but during handleInvocation the listener's notify(DelegateTask) throws — e.g. NPE inside the listener, failed dependency injection, DB/service call failure inside the listener body.
Common situations: Listener code assuming injected fields/variables are non-null; listener calling an external service that fails; exceptions in Spring bean initialization during expression resolution; delegate interceptor wrapping adding behavior (transactions, security) that throws.
Related errors
- Delegate expression " + expression + " did not resolve to…
- Delegate expression did not resolve to an implementation of…
- ${exc.getMessage()}
- Could not execute inner activity behavior of multi instance…
- Couldn't execute listener
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/d5ca7c450f51804e.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/listener/DelegateExpressionTaskListener.java:53
public DelegateExpressionTaskListener(Expression expression, List<FieldDeclaration> fieldDeclarations) {
this.expression = expression;
this.fieldDeclarations = fieldDeclarations;
}
@Override
public void notify(DelegateTask delegateTask) {
// Note: we can't cache the result of the expression, because the
// execution can change: eg. delegateExpression='${mySpringBeanFactory.randomSpringBean()}'
Object delegate = expression.getValue(delegateTask);
ClassDelegate.applyFieldDeclaration(fieldDeclarations, delegate);
if (delegate instanceof TaskListener) {
try {
Context.getProcessEngineConfiguration()
.getDelegateInterceptor()
.handleInvocation(new TaskListenerInvocation((TaskListener) delegate, delegateTask));
} catch (Exception e) {
throw new ActivitiException("Exception while invoking TaskListener: " + e.getMessage(), e);
}
} else {
throw new ActivitiIllegalArgumentException("Delegate expression " + expression
+ " did not resolve to an implementation of " + TaskListener.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 d6d39ce1c6)