handler-bind
(handler-bind ((type handler)...) body...)
Evaluates body... with the handlers established. When a condition is signaled during the body — by error, signal, warn or cerror — each matching handler is called at the signal point, before any unwinding, with the condition object as its one argument. That is the difference from handler-case: the stack between the signaler and the handler is still intact, so the handler can invoke-restart a restart established by a restart-case inside the body and transfer control there. A handler that returns normally declines: the search continues with outer handlers, and an unhandled error then aborts (or is caught by an enclosing handler-case) exactly as if no handler-bind were present. The type is any handler-case clause type, including classes from define-condition and the class a built-in error carries (type-error, division-by-zero, ... -- see handler-case); the handler expressions are evaluated when the handler-bind is entered.
Supported on every backend except --no-gc. A program using the restart system compiles in EH mode on the wasm-GC backends, so add -W exceptions=y to wasmtime run/wasmtime serve. Handlers also run for the errors built-ins raise (a (car 5)-style type error, an out-of-range aref, an undefined function): the interpreter runs them at the signal point like a signaled condition; the compiled backends run them when the error unwinds past the handler-bind itself, so restarts established inside the body are gone and intervening unwind-protect cleanups have already run by then (a signaled condition keeps the exact signal-point semantics everywhere). On the wasm-GC backends a failure that traps instead of signaling ((car 5) compiles to a failed cast; so does integer division by zero) still ends the program without running handlers — only what rides the condition channel (signaled conditions, an undefined-function call) reaches them.
A handler that returns declines, and the error keeps propagating:
Handlers run most recent first, and a handler-case established inside the body is one of them: a condition it matches is handled there and the enclosing handler is never called. Only when no clause of the inner handler-case matches does the search reach the outer handler.
An error a built-in raises runs the handlers too — how a test framework turns a broken test body into a recorded failure instead of an aborted run: