Build1 publisher2 min readPublished
Angular 22.2 adds @boundary to keep one failing component from blanking the page
Angular 22.2 ships @boundary, a template block that replaces a component that throws while rendering with a fallback and a $reset() retry. Its developer-preview syntax can still change, so it suits prototypes now and production once it goes stable.
The Engineer · Build desk
Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction
What happened
- Until 22.2, a component that threw during rendering took the whole view with it, and a global ErrorHandler could log the crash but not restore the screen.
- Several @error blocks can be chained under one boundary, each with a when condition, and the first whose condition is truthy renders its fallback.
- When no @error block matches, Angular throws a BoundaryError carrying the original error as its cause and passes it to the next boundary up.
- Calling value() on a resource() in an error state throws instead of returning undefined, so a boundary can catch failed data loads without an @if around error().
- Caught errors still reach ErrorHandler.onViewError, or handleError if that is absent, with details naming the failed declaration and the catching boundary.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint Templates written against @boundary in 22.2 may need rewriting if its syntax or behaviour changes before stable, so production adoption now carries a migration cost paid later.
- exposure An existing ErrorHandler that updates signals becomes a failure source inside every boundary, so adopting the feature means auditing the reporting path along with the templates.
- decision Teams on resource() can collapse per-binding error checks into one @error block per view, while still writing a loading guard for each resource.
The catch scope covers anything Angular does while creating or updating the views inside the block [12]. That includes component constructors, template bindings, lifecycle hooks, @for expressions, effects declared inside the boundary, and components created lazily or dynamically [12]. When one of those throws, Angular walks up the view tree to the closest boundary [13]. If that boundary's handlers do not match, or throw themselves, the walk continues [13]. That part is well designed. A narrow handler next to one chart cannot swallow a failure it was never written for.
The fallback API is small. Anything thrown that is not an Error arrives wrapped in an ErrorBoundaryWrappedError, so reading $error.message inside the fallback cannot itself throw [5]. The let alias from the June teaser still works, and $error and $reset are the only names allowed [7]. A typo in the variable name has nowhere to go. The when clause takes any template expression, usually a component method such as isChartError(err) [9]. Only the last @error in a chain may be unconditional [10].
The documentation already has a rough edge. According to the dev.to walkthrough, the official error-boundaries guide pairs an isRenderError(err) condition with a "Network issue" message, and readers should not copy it verbatim [18].
The trap I would test first is in reporting. onViewError runs synchronously while Angular is rendering [15]. If it writes to a signal, say for an on-screen error list or a store, Angular raises NG0600 and the boundary that was trying to report the error breaks [15]. An error reporter that causes an error inside the error boundary makes for an awkward bug report. The walkthrough's fix is to defer the write with queueMicrotask() or send the error straight to monitoring [15].
The resource() integration is where the feature fits the rest of the framework, with one guard left over. value() throws only in the error state, so the template still has to handle the first load itself [17]. The walkthrough wraps its summary component in @if (order.isLoading() && !order.hasValue()). Its retry button calls order.reload() before $reset() [17].
@boundary first appeared in 22.2.0-next.6 [1]. In June the same author advised against counting on it in production yet [19]. Shipping in a minor release has not changed its status. Syntax and behaviour can still change before it goes stable [2], and the walkthrough does not say when that will happen. In a codebase where error reporting writes to app state, I would put a boundary on one non-critical view now, check the companion demo's on-screen log of where each error ends up [20], and keep production templates off it until the preview label comes off.
What to watch
- Whether @boundary's syntax or behaviour changes between 22.2 and the release that drops the developer-preview label.
- Whether the official error-boundaries guide corrects its isRenderError(err) example paired with a "Network issue" message.
- Whether a later release makes signal writes from onViewError safe or documents the queueMicrotask() deferral in the framework guide.