catch
(catch tag body...)
Establishes a dynamic exit point named by tag and returns the value of the last body form -- or, if a throw to an eq tag fires anywhere in the body's dynamic extent, the thrown value. The tag is an ordinary runtime value evaluated once on entry (usually a quoted symbol), so unlike block/return-from the thrower does not need the catcher in lexical scope: it only has to run while the catch is active. The innermost active catch with a matching tag wins; a non-matching one lets the exit pass through.
catch/throw work on every backend except --no-gc (a compile error there). On the wasm-GC backends (Preview 1 and --component) they compile through the WebAssembly exception-handling proposal, so running a program that uses them needs wasmtime 37+ with -W exceptions=y, exactly like unwind-protect and handler-case.
A throw is a non-local exit, not a condition: it unwinds through a handler-case without being caught, while every intervening unwind-protect cleanup does run.
The exit crosses function boundaries, which is what makes it useful for bailing out of a callback:
Tags are compared with eq, so a freshly consed tag matches only itself: