Pedestal must do something useful when an interceptor throws an
exception. It would not be useful to bubble up the runtime call stack,
because that call stack only includes the Pedestal machinery
itself. Interceptors are data structures that conceptually represent
frames on a call stack, but they are not present in the usual
nested fashion on the Java call stack.
Remember that request processing may be asynchronous, in which case
the call stack doesn’t even represent the flow of control to the point
where the exception occurred.
Instead, Pedestal works backwards, looking for an interceptor to handle
the exception. All exceptions thrown from an
interceptor are captured; Pedestal wraps such exceptions in an ExceptionInfo
instance
which is then bound to the :io.pedestal.interceptor.chain/error key
in the context map.
As long as there is an error attached to that key, Pedestal will not
invoke the usual :enter and :leave functions. Instead, it looks
for the next interceptor in the chain that has an :error function
attached to it.
This error handling proceeds the same way regardless of whether
interceptors in the chain returned a context map or
async channel. (See
Interceptor Return
Values for details on async return.) As a result, Pedestal unifies
error handling for synchronous interceptors and asynchronous
interceptors.
You can supply your own :error handling interceptor anywhere in the interceptor queue.