@@ -158,26 +158,45 @@ public String getWorkspacePath() {
158158 * <p>
159159 * When an event handler registered via {@link #on(Consumer)} or
160160 * {@link #on(Class, Consumer)} throws an exception during event dispatch, the
161- * error handler is invoked instead of the default behavior (logging at
162- * {@link Level#SEVERE}).
161+ * error handler is invoked to handle the error. The handler's return value
162+ * controls whether dispatch continues to remaining handlers:
163+ * <ul>
164+ * <li>Return {@code true} to continue dispatching (default behavior for
165+ * independent listeners)</li>
166+ * <li>Return {@code false} to stop dispatching (short-circuit for validation
167+ * or critical errors)</li>
168+ * </ul>
163169 *
164170 * <p>
165- * If the error handler itself throws an exception, that exception is silently
166- * caught and logged to prevent cascading failures.
171+ * When no error handler is set, exceptions are silently caught and dispatch
172+ * continues. Applications should set an error handler to log, track, or respond
173+ * to handler failures.
174+ *
175+ * <p>
176+ * If the error handler itself throws an exception, that exception is caught,
177+ * logged at {@link Level#SEVERE}, and dispatch is stopped to prevent cascading
178+ * failures.
167179 *
168180 * <p>
169181 * <b>Example:</b>
170182 *
171183 * <pre>{@code
184+ * // Continue on error (log and keep dispatching)
185+ * session.setEventErrorHandler((event, exception) -> {
186+ * logger.error("Handler failed: {}", exception.getMessage(), exception);
187+ * return true; // keep dispatching
188+ * });
189+ *
190+ * // Short-circuit on error (stop at first failure)
172191 * session.setEventErrorHandler((event, exception) -> {
173- * metrics.increment("handler.errors" );
174- * logger.error("Handler failed on {}: {}", event.getType(), exception.getMessage());
192+ * logger.error("Handler failed, stopping: {}", exception.getMessage(), exception );
193+ * return false; // stop dispatching
175194 * });
176195 * }</pre>
177196 *
178197 * @param handler
179- * the error handler, or {@code null} to restore default logging
180- * behavior
198+ * the error handler, or {@code null} to restore default silent
199+ * continuation behavior
181200 * @see EventErrorHandler
182201 * @since 1.0.8
183202 */
@@ -330,8 +349,10 @@ public CompletableFuture<AssistantMessageEvent> sendAndWait(MessageOptions optio
330349 * instead.
331350 *
332351 * <p>
333- * <b>Exception isolation:</b> If a handler throws an exception, the error is
334- * logged and remaining handlers still execute.
352+ * <b>Exception handling:</b> If a handler throws an exception, the error is
353+ * routed to the configured {@link EventErrorHandler} (if set), which can choose
354+ * to continue or stop dispatching. When no error handler is set, exceptions are
355+ * silently caught and remaining handlers still execute.
335356 *
336357 * <p>
337358 * <b>Example:</b>
@@ -347,6 +368,7 @@ public CompletableFuture<AssistantMessageEvent> sendAndWait(MessageOptions optio
347368 * @return a Closeable that, when closed, unsubscribes the handler
348369 * @see #on(Class, Consumer)
349370 * @see AbstractSessionEvent
371+ * @see #setEventErrorHandler(EventErrorHandler)
350372 */
351373 public Closeable on (Consumer <AbstractSessionEvent > handler ) {
352374 eventHandlers .add (handler );
@@ -361,8 +383,10 @@ public Closeable on(Consumer<AbstractSessionEvent> handler) {
361383 * matching the specified type.
362384 *
363385 * <p>
364- * <b>Exception isolation:</b> If a handler throws an exception, the error is
365- * logged and remaining handlers still execute.
386+ * <b>Exception handling:</b> If a handler throws an exception, the error is
387+ * routed to the configured {@link EventErrorHandler} (if set), which can choose
388+ * to continue or stop dispatching. When no error handler is set, exceptions are
389+ * silently caught and remaining handlers still execute.
366390 *
367391 * <p>
368392 * <b>Example Usage</b>
@@ -394,6 +418,7 @@ public Closeable on(Consumer<AbstractSessionEvent> handler) {
394418 * @return a Closeable that unsubscribes the handler when closed
395419 * @see #on(Consumer)
396420 * @see AbstractSessionEvent
421+ * @see #setEventErrorHandler(EventErrorHandler)
397422 */
398423 public <T extends AbstractSessionEvent > Closeable on (Class <T > eventType , Consumer <T > handler ) {
399424 Consumer <AbstractSessionEvent > wrapper = event -> {
@@ -410,11 +435,20 @@ public <T extends AbstractSessionEvent> Closeable on(Class<T> eventType, Consume
410435 * <p>
411436 * This is called internally when events are received from the server. Each
412437 * handler is invoked in its own try/catch block so that an exception thrown by
413- * one handler does not prevent subsequent handlers from executing.
438+ * one handler does not prevent subsequent handlers from executing by default .
414439 * <p>
415440 * If a custom {@link EventErrorHandler} has been set via
416441 * {@link #setEventErrorHandler(EventErrorHandler)}, it is called with the event
417- * and exception. Otherwise, exceptions are logged at {@link Level#SEVERE}.
442+ * and exception. The error handler's return value controls whether dispatch
443+ * continues:
444+ * <ul>
445+ * <li>{@code true} - continue dispatching to remaining handlers</li>
446+ * <li>{@code false} - stop dispatching (short-circuit)</li>
447+ * </ul>
448+ * <p>
449+ * When no error handler is set, exceptions are silently caught and dispatch
450+ * continues. If the error handler itself throws an exception, dispatch is
451+ * stopped and the error is logged at {@link Level#SEVERE}.
418452 *
419453 * @param event
420454 * the event to dispatch
@@ -428,13 +462,15 @@ void dispatchEvent(AbstractSessionEvent event) {
428462 EventErrorHandler errorHandler = this .eventErrorHandler ;
429463 if (errorHandler != null ) {
430464 try {
431- errorHandler .handleError (event , e );
465+ if (!errorHandler .handleError (event , e )) {
466+ break ; // stop dispatching
467+ }
432468 } catch (Exception errorHandlerException ) {
433469 LOG .log (Level .SEVERE , "Error in event error handler" , errorHandlerException );
470+ break ; // error handler itself failed — stop to be safe
434471 }
435- } else {
436- LOG .log (Level .SEVERE , "Error in event handler" , e );
437472 }
473+ // No error handler set: continue silently (no logging)
438474 }
439475 }
440476 }
0 commit comments