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
- Add the event attribute to the taskListener element in the BPMN XML (event="create", "assignment", "complete", "delete", or "all")
- If adding listeners in code, call .event(TaskListener.EVENTNAME_ALL_EVENTS) or a specific event on the listener builder
- 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
- Always set event (or "all") on every taskListener element
- Validate BPMN XML against the Flowable XSD before deployment
- Use the Flowable Modeler which enforces the event attribute
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
- Delegate expression " + expression + " did not resolve to…
- Delegate expression did not resolve to an implementation of…
- Exception while invoking TaskListener
- No TaskListener implementation found for…
- One of the attributes 'class', 'delegateExpression'…
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)