flowable/flowable-engine · error · FlowableIllegalStateException

No event defined for taskListener in UserTask '" +…

Error message

No event defined for taskListener in UserTask '" + userTask.getName() + "'. Line: " + listener.getXmlRowNumber()

What it means

When executing task listeners for a user task, ListenerNotificationHelper checks that each FlowableListener declares an event. If listener.getEvent() is null, it throws FlowableIllegalStateException, because without an event the listener can never be matched to a lifecycle moment.

Solutions

  1. Add the event attribute to the taskListener element in the BPMN XML (event="create", "assignment", "complete", "delete", or "all")
  2. If adding listeners in code, call .event(TaskListener.EVENTNAME_ALL_EVENTS) or a specific event on the listener builder
  3. Validate the deployed XML against the flowable XSD before deployment to catch the missing attribute

Example fix

// before
<flowable:taskListener class="com.example.MyListener" />
// after
<flowable:taskListener event="create" class="com.example.MyListener" />
Defensive patterns

Strategy: validation

Validate before calling

for (FlowableListener l : userTask.getTaskListeners()) {
    if (l.getEvent() == null) throw new IllegalStateException("taskListener missing event attr in " + userTask.getId());
}

Type guard

boolean hasEvent(FlowableListener l) { return l.getEvent() != null; }

Try / catch

try {
    runtimeService.startProcessInstanceByKey("myProcess");
} catch (FlowableIllegalStateException e) {
    if (e.getMessage().startsWith("No event defined for taskListener")) {
        log.error("BPMN XML has taskListener without event attribute: {}", e.getMessage());
    }
}

Prevention

When it happens

Trigger: A <flowable:taskListener> element in the BPMN XML is missing the required 'event' attribute (e.g. <flowable:taskListener class="..."/> with no event="create|assignment|complete|delete|all").

Common situations: Hand-edited or generated BPMN XML omitting the event attribute; modeler export dropping the attribute; listener added programmatically via builder without .event(...).

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/listener/ListenerNotificationHelper.java:119

        addTransactionListener(listener, new ExecuteExecutionListenerTransactionListener(executionListener, scope, 
                        CommandContextUtil.getProcessEngineConfiguration().getCommandExecutor()));
    }

    public void executeTaskListeners(TaskEntity taskEntity, String eventType) {
        if (taskEntity.getProcessDefinitionId() != null) {
            org.flowable.bpmn.model.Process process = ProcessDefinitionUtil.getProcess(taskEntity.getProcessDefinitionId());
            FlowElement flowElement = process.getFlowElement(taskEntity.getTaskDefinitionKey(), true);
            if (flowElement instanceof UserTask userTask) {
                executeTaskListeners(userTask, taskEntity, eventType);
            }
        }
    }

    public void executeTaskListeners(UserTask userTask, TaskEntity taskEntity, String eventType) {
        for (FlowableListener listener : userTask.getTaskListeners()) {
            String event = listener.getEvent();
            if (event == null) {
                throw new FlowableIllegalStateException(
                        "No event defined for taskListener in UserTask '" + userTask.getName() + "'. Line: " + listener.getXmlRowNumber());
            }
            if (event.equals(eventType) || event.equals(TaskListener.EVENTNAME_ALL_EVENTS)) {
                BaseTaskListener taskListener = createTaskListener(listener);

                if (listener.getOnTransaction() != null) {
                    ExecutionEntity executionEntity = CommandContextUtil.getExecutionEntityManager().findById(taskEntity.getExecutionId());
                    planTransactionDependentTaskListener(executionEntity, (TransactionDependentTaskListener) taskListener, listener);
                } else {
                    taskEntity.setEventName(eventType);
                    taskEntity.setEventHandlerId(listener.getId());
                    
                    try {
                        CommandContextUtil.getProcessEngineConfiguration().getDelegateInterceptor()
                                .handleInvocation(new TaskListenerInvocation((TaskListener) taskListener, taskEntity));
                    } finally {
                        taskEntity.setEventName(null);
                    }

View on GitHub (pinned to d6d39ce1c6)