flowable/flowable-engine · error · ActivitiException

Exception while invoking TaskListener:

Error message

Exception while invoking TaskListener: 

What it means

Wraps any Exception raised while invoking a registered TaskListener during task events (create/complete/assignment etc.). The engine routes the listener through the configured DelegateInterceptor; if the listener's notify() throws, it is rethrown as an ActivitiException with the delegate's message. The original exception is kept as the cause, so the real failure is in your listener code.

Solutions

  1. Inspect the cause (getCause()) of this exception — the real bug is inside your TaskListener's notify() method
  2. Fix or add error handling/logging in the listener implementation before it rethrows
  3. Verify any delegateExpression beans exist and are injectable in the current context
  4. Test the listener logic in isolation with a unit test calling notify(DelegateTask)

Example fix

// before: listener that throws
public void notify(DelegateTask task) {
    String val = (String) task.getVariable("missing"); // NPE risk
    doWork(val.toLowerCase());
}
// after: defensive listener
public void notify(DelegateTask task) {
    Object val = task.getVariable("missing");
    if (val == null) { LOG.warn("variable missing, skipping"); return; }
    doWork(val.toString().toLowerCase());
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify listener bean/expr resolves before deploy
Object bean = applicationContext.getBean(listenerBeanName); // throws early if missing

Try / catch

try {
    taskService.complete(taskId);
} catch (ActivitiException e) {
    Throwable root = e; while (root.getCause() != null) root = root.getCause();
    LOG.error("TaskListener failed: " + root.getMessage(), root);
}

Prevention

When it happens

Trigger: A custom TaskListener (class, expression, or delegateExpression) throws any exception during fireEvent(TaskListener.EVENTNAME_*) — typically on task creation, completion, or assignment inside TaskEntity.

Common situations: NullPointerException inside listener code; listener delegateExpression points to a bean that fails to resolve; listener calls engine APIs that themselves fail; classpath issues loading the listener class; the DelegateInterceptor throws (e.g. custom security interceptor).

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/325058e19e933a92. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/persistence/entity/TaskEntity.java:777

        this.formKey = formKey;
    }

    public void fireEvent(String taskEventName) {
        TaskDefinition taskDefinition = getTaskDefinition();
        if (taskDefinition != null) {
            List<TaskListener> taskEventListeners = getTaskDefinition().getTaskListener(taskEventName);
            if (taskEventListeners != null) {
                for (TaskListener taskListener : taskEventListeners) {
                    ExecutionEntity execution = getExecution();
                    if (execution != null) {
                        setEventName(taskEventName);
                    }
                    try {
                        Context.getProcessEngineConfiguration()
                                .getDelegateInterceptor()
                                .handleInvocation(new TaskListenerInvocation(taskListener, (DelegateTask) this));
                    } catch (Exception e) {
                        throw new ActivitiException("Exception while invoking TaskListener: " + e.getMessage(), e);
                    }
                }
            }
        }
    }

    @Override
    protected boolean isActivityIdUsedForDetails() {
        return false;
    }

    // Override from VariableScopeImpl

    // Overridden to avoid fetching *all* variables (as is the case in the super call)
    @Override
    protected VariableInstanceEntity getSpecificVariable(String variableName) {
        CommandContext commandContext = Context.getCommandContext();
        if (commandContext == null) {

View on GitHub (pinned to d6d39ce1c6)