gradle/gradle · error · ListenerNotificationException
Failed to notify {typeDescription}.
Error message
Failed to notify {typeDescription}. What it means
AbstractBroadcastDispatch wraps every listener notification; when a listener method wrapped in UncheckedException throws, dispatch(...) unwraps the cause and rethrows it inside a ListenerNotificationException whose message is 'Failed to notify <type description>.' — the listener interface's simple name split on camel case and lowercased (TestListener -> 'test listener'). This keeps one listener's failure from silently vanishing while branding it as a notification problem.
Source
Thrown at platforms/core-runtime/messaging/src/main/java/org/gradle/internal/event/AbstractBroadcastDispatch.java:46
import java.util.Locale;
public abstract class AbstractBroadcastDispatch<T> implements Dispatch<MethodInvocation> {
protected final Class<T> type;
public AbstractBroadcastDispatch(Class<T> type) {
this.type = type;
}
private String getErrorMessage() {
String typeDescription = type.getSimpleName().replaceAll("(\\p{Upper})", " $1").trim().toLowerCase(Locale.ROOT);
return "Failed to notify " + typeDescription + ".";
}
protected void dispatch(MethodInvocation invocation, Dispatch<MethodInvocation> handler) {
try {
handler.dispatch(invocation);
} catch (UncheckedException e) {
throw new ListenerNotificationException(invocation, getErrorMessage(), Collections.singletonList(e.getCause()));
} catch (BuildOperationInvocationException e) {
throw new ListenerNotificationException(invocation, getErrorMessage(), Collections.singletonList(e.getCause()));
} catch (RuntimeException t) {
throw t;
} catch (Throwable t) {
throw new ListenerNotificationException(invocation, getErrorMessage(), Collections.singletonList(t));
}
}
/**
* Dispatch an invocation to the given dispatchers.
* <p>
* This method will try to dispatch the invocation in an efficient way based on the number of dispatchers.
* </p>
*/
protected void dispatch(MethodInvocation invocation, List<? extends Dispatch<MethodInvocation>> dispatchers) {
switch (dispatchers.size()) {
case 0:View on GitHub (pinned to 534f27719b)
Solutions
- Read the wrapped cause (first element of the exception's causes) — its stack trace names the failing listener class and method
- Fix the listener: guard nulls and event types so callbacks never throw
- Remove or update the offending plugin if you do not own the listener code
- If you own the dispatch site, catch ListenerNotificationException and process all its causes instead of losing them
Example fix
// before
public void afterTest(TestDescriptor td, TestResult tr) {
report.record(td.getDisplayName().length()); // NPE when displayName is null
}
// after
public void afterTest(TestDescriptor td, TestResult tr) {
String name = td.getDisplayName();
if (name != null) report.record(name.length());
} Defensive patterns
Strategy: try-catch
Try / catch
try {
broadcast.dispatch(invocation);
} catch (ListenerNotificationException e) {
Throwable cause = e.getCauses().get(0); // original listener failure, unwrapped from UncheckedException
LOGGER.error("Notification failed", cause);
// decide: rethrow, or continue if the build must survive listener errors
} Prevention
- Keep listener callback bodies exception-free: guard nulls and instanceof before casting
- Log and return from listeners instead of throwing
- Test listeners against the exact Gradle version you target, since event contracts evolve
When it happens
Trigger: Any registered listener throwing an UncheckedException-wrapped error during a broadcast notification, e.g. a TestListener failing inside afterTest or a BuildListener failing in buildFinished.
Common situations: Plugin listeners throwing NPEs on unexpected input; listeners assuming non-null domain objects that later Gradle versions make nullable; test listeners breaking on new event types.
Related errors
- One or more build phasedAction listeners failed with an exce
- Cannot call %s on %s as changes to this collection are disal
- Cannot add a %s with name '%s' as a %s with that name alread
- Cannot create a %s named '%s' because this container does no
- Cannot create a %s because this type is not known to %s. Kno
AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22).
Data as JSON: /api/errors/5fa92ae980a788ca.
Report an issue: GitHub.