{"record":{"id":"d5a440d6bd5e306e","repo":"SonarSource/sonarqube","slug":"broadcasting-to-listeners-failed-for-s-events","errorCode":null,"errorMessage":"Broadcasting to listeners failed for %s events","messagePattern":"Broadcasting to listeners failed for (.+?) events","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/sonar-webserver-api/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImpl.java","lineNumber":61,"sourceCode":"public class QGChangeEventListenersImpl implements QGChangeEventListeners {\n  private static final Logger LOG = LoggerFactory.getLogger(QGChangeEventListenersImpl.class);\n\n  private final Set<QGChangeEventListener> listeners;\n\n  public QGChangeEventListenersImpl(Set<QGChangeEventListener> listeners) {\n    this.listeners = listeners;\n  }\n\n  @Override\n  public void broadcastOnIssueChange(List<DefaultIssue> issues, Collection<QGChangeEvent> changeEvents, boolean fromAlm) {\n    if (listeners.isEmpty() || issues.isEmpty() || changeEvents.isEmpty()) {\n      return;\n    }\n\n    try {\n      broadcastChangeEventsToBranches(issues, changeEvents, fromAlm);\n    } catch (Error e) {\n      LOG.warn(format(\"Broadcasting to listeners failed for %s events\", changeEvents.size()), e);\n    }\n  }\n\n  @Override\n  public void broadcastOnAnyChange(Collection<QGChangeEvent> changeEvents, boolean fromAlm) {\n    if (listeners.isEmpty() || changeEvents.isEmpty()) {\n      return;\n    }\n\n    try {\n      for (var changeEvent : changeEvents) {\n        listeners.forEach(listener -> broadcastChangeEventToListener(Set.of(), changeEvent, listener));\n      }\n    } catch (Error e) {\n      LOG.warn(format(\"Broadcasting to listeners failed for %s events\", changeEvents.size()), e);\n    }\n  }\n","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-api/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImpl.java#L43-L79","documentation":"QGChangeEventListenersImpl.broadcastOnIssueChange forwards quality-gate change events to registered listeners. If the broadcast loop throws a java.lang.Error, it is caught and logged as a warning with the number of events, so listener failures never break issue processing.","triggerScenarios":"Any issue change triggering quality-gate events where broadcastChangeEventsToBranches (or a listener's onChange) throws an Error (e.g. NoClassDefFoundError, OutOfMemoryError) rather than a checked/regular Exception.","commonSituations":"A misbehaving third-party or custom QGChangeEventListener classpath conflict; JVM resource exhaustion during large issue batch processing.","solutions":["Inspect the logged stack trace to find which listener or JVM Error caused the failure.","Fix or remove the faulty listener plugin causing NoClassDefFoundError/LinkageError.","If OutOfMemoryError, increase SonarQube JVM heap (SONAR_WEB_JAVAMEMOPT) or reduce batch size.","Retry the affected issue computation after fixing; events are only lost for this broadcast."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// callers are already protected, but custom listeners should self-guard\ntry {\n  listener.onIssueChanges(event, issues);\n} catch (Throwable t) {\n  LOG.warn(\"QG listener failed\", t);\n}","preventionTips":["Keep custom QGChangeEventListener implementations defensive (catch their own exceptions)","Monitor logs for LinkageError/OOM after SonarQube upgrades","Ensure listener plugin dependencies do not clash with core classpath"],"tags":["sonarqube","quality-gate","listeners","jvm-error"],"backgroundTag":"internal-invariant-violation","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}