Back to News & Insights
Web Development October 2, 2026 · 5 min read

Template errors: React and Next.js vs Angular 22.2's @boundary

A dashboard with three widgets. The sales widget reads data.points.length, and one day the backend...

Template errors: React and Next.js vs Angular 22.2's @boundary

A dashboard with three widgets. The sales widget reads data.points.length, and one day the backend returns { points: null }. On render, null.length throws a TypeError.

The question is what the user sees: the whole screen broken, or just that widget with an error message. Each framework answers differently, and the answer says a lot about how each one is designed.

If a component throws while rendering and nobody catches it, React removes the whole UI from the screen. To prevent that, there's the Error Boundary: a component that implements getDerivedStateFromError to show a fallback and componentDidCatch to log the error.

Two details that surprise people coming from hooks: It has to be a class. The React docs say it plainly: there's currently no way to write an Error Boundary as a function component. The usual way out is the react-error-boundary library. It doesn't catch everything. Event handlers, async code (setTimeout), server-side rendering and errors thrown by the boundary itself are left out. The exception is the startTransition returned by useTransition: errors thrown there do reach the boundary (the standalone startTransition imported from react doesn't: it goes to reportError).

Why it works this way: in React, error handling lives in the component lifecycle. Hooks have no equivalent of getDerivedStateFromError, so the only piece that can catch its children's errors is a class component.

Next.js builds its boundaries on top of folder-based routing. An error.tsx inside a segment wraps that segment's page and its children in a boundary; it doesn't cover the layout.tsx of the same segment, which is handled by the parent's error.tsx (Next.js 16.3 docs):

Errors bubble up to the nearest error.tsx, and global-error.tsx covers the root layout. To contain errors at the component level, not just the route level, Next.js has catchError (stable since 16.3), which turns a function into a boundary without writing the class.

Why it works this way: in Next.js, the structure of the app is its folders. It makes sense for the route segment to be the natural unit of error.

Angular only had ErrorHandler.handleError(): a central place to find out about an error and report it, but no built-in way to replace the broken part with a local fallback. As Ninja Squad describes it, if a component threw while rendering, the rest of its subtree wasn't rendered and the page ended up partially blank.

Angular 22.2, released on September 23, 2026, adds @boundary in developer preview (official guide):

Only the sales box shows the fallback; users and alerts render normally. The @error blocks are evaluated in order, and if none matches and there's no @error without when at the end, the error keeps going, wrapped in a BoundaryError with the original in .cause.

According to the framework's tests, the block catches errors thrown by the constructors of the components inside it, their lifecycle hooks, template bindings and their effect()s.

| Piece | What it's for | |---|---| | @boundary / @error | The declarative version, in the template | | onError in createComponent and createEmbeddedView | The equivalent for views created in code: you get the error in a callback and build the fallback yourself. It doesn't cover the creation phase (the constructor, or creating the view in createEmbeddedView): that throws synchronously from the same call | | ErrorHandler.onViewError() | Optional hook that receives every error a boundary intercepts, so you can send it to monitoring. If you implement it, those errors no longer go through handleError(); if you don't, they go there |

Why it works this way: in Angular, the template compiler already owns control flow (@if, @for, @defer), and a boundary is one more block, not a component. The programmatic API completes the picture: a component you insert into a ViewContainerRef located inside a @boundary is already covered (a framework test checks exactly that), but not every dynamic view has a block around it, and that's what onError is for.

Where to put them: Angular's guide doesn't say, but react.dev's criterion applies just as well. You don't need to wrap every component: a boundary goes where it makes sense to show an error message, like a widget or a third-party component. And errors you can anticipate, like a failing fetch, Angular recommends handling where they happen, with try/catch. The ErrorHandler is for reporting the unexpected.

This section is opinion: You don't need a class or a library. It's template syntax, just like @if. You discriminate by error type in the template. Several @error (when ...) blocks with a catch-all at the end. In React, that logic goes inside the fallback. Declarative, programmatic and global are part of the same feature. No need to assemble the puzzle from loose pieces.

To be fair: @boundary is in developer preview: per the versioning policy, it can change even in a patch release. React's boundaries have years in production. Next.js's catchError already solves the "I don't want to write a class" problem. And React also has a global callback: createRoot accepts onCaughtError, which receives the errors a boundary catches. It doesn't catch event handlers either. In Angular 22.2's code, an error inside a listener goes straight to the global ErrorHandler, without going through any boundary (listeners.ts). Same limit as React. Watch out for content projection. Wrapping in a @boundary doesn't catch errors from projected content: that content belongs to the view that declares it. You have to wrap the container component from the parent template (guide). In React, a boundary that wraps children does catch their errors.

Summary React: a class component, or react-error-boundary. Next.js: error.tsx per route and catchError per component. Angular 22.2: a template block, with a programmatic equivalent and a global hook.

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation