Interface HandlerInterceptor

Functional Interface:
This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

@Experimental @FunctionalInterface public interface HandlerInterceptor
Wraps a single handler invocation attempt. Implementations must invoke HandlerInterceptor.Next.proceed() exactly once.

Typical use is to start a span / observation / MDC scope before proceed() and finalize it after, e.g.:


 (ctx, next) -> {
   Span span = tracer.startSpan(...);
   try (Scope s = span.makeCurrent()) {
     next.proceed();
     span.setStatus(OK);
   } catch (Exception e) {
     span.setStatus(ERROR);
     throw e;
   } finally {
     span.end();
   }
 }
 

Errors visible to the interceptor

The interceptor sees all errors except protocol errors occuring during invocation processing, for example:
  • Request/Response serialization/deserialization failures.
  • If the user handler throws, proceed() rethrows that exception unchanged.
  • Errors from an innermost interceptor.

Transforming errors

Interceptors can catch a Exception from proceed() and rethrow a different one.

A common pattern is to convert known-unrecoverable exceptions (e.g., IllegalArgumentException from input validation) into TerminalException.

⚠ Never catch or remap AbortedExecutionException

AbortedExecutionException is an internal SDK control-flow signal used to abort the current execution attempt during journal replay and suspension. Remapping it will corrupt the state machine and produce non-deterministic behavior. If you catch it, rethrow it as it is.