Not Found, Redirects, and Error Boundaries

Purpose and Scope

This page explains the Router error-control path: how TanStack Router represents missing routes, missing data, redirects, and render-time exceptions. The reader problem is usually not just how to show an error screen, but where to place that screen so the application keeps the right layout, preserves useful context, and remains type-safe when a loader or guard decides navigation cannot continue. TanStack Router treats these outcomes as first-class route events rather than as unrelated ad hoc component state, so the same route tree that defines matching and layouts also determines where not-found and error UI appears.

Sources: docs/router/guide/not-found-errors.md, docs/router/api/router/notFoundFunction.md, docs/router/api/router/redirectFunction.md, docs/router/api/router/errorComponentComponent.md, docs/router/api/router/catchBoundaryComponent.md

The not-found guide distinguishes two cases that look similar to users but originate from different parts of the system. A non-matching pathname is detected by the router when the URL does not match a known route pattern, or when it partially matches but includes extra path segments. A missing resource is detected by application code, typically inside a route beforeLoad or loader, when a record, document, or other asynchronous dependency does not exist. Both cases use the newer notFound function and notFoundComponent API; the older NotFoundRoute is documented as deprecated.

Sources: docs/router/guide/not-found-errors.md, docs/router/api/router/notFoundFunction.md

Relevant Source Files

  • docs/router/guide/not-found-errors.md - Defines the not-found model, notFoundMode, fuzzy versus root handling, missing-resource behavior, and migration direction away from NotFoundRoute.
  • docs/router/api/router/notFoundFunction.md - Documents the notFound function, its optional Partial<NotFoundError> options object, return-versus-throw behavior, and examples in route loaders.
  • docs/router/api/router/redirectFunction.md - Documents the redirect function, required Redirect options, internal and external redirects, route-bound redirects, and getRouteApi().redirect.
  • docs/router/api/router/errorComponentComponent.md - Documents ErrorComponent props and default display behavior for caught errors.
  • docs/router/api/router/catchBoundaryComponent.md - Documents CatchBoundary props, reset behavior, fallback rendering, and onCatch callback behavior.

Not-Found Handling Model

A not-found error is not limited to a global 404 page. In fuzzy mode, which the guide identifies as the default, TanStack Router tries to preserve as much parent layout as possible by finding the nearest suitable matched route with a configured notFoundComponent, or by using the router's defaultNotFoundComponent when configured. This matters for nested applications: a bad child path below /posts/$postId can still render the root layout, the posts layout, and the post layout before showing the most local not-found UI. The user remains oriented in the part of the app they attempted to visit.

Sources: docs/router/guide/not-found-errors.md

The alternative notFoundMode: 'root' changes that placement decision. Instead of bubbling to the nearest fuzzy-matched route, all automatic path-not-found errors are handled by the root route's notFoundComponent. That can be appropriate for applications that want a single full-page 404 treatment, but it gives up the locality that fuzzy mode is designed to preserve. In practice, choose fuzzy mode when nested layouts are navigationally meaningful, and choose root mode when any unknown URL should escape the section-specific layout and show a uniform site-level result.

Sources: docs/router/guide/not-found-errors.md

Missing resources require an explicit signal from application code. If a loader fetches a post by ID and the post is absent, the router cannot infer whether the route should show a not-found UI, an empty state, a redirect, or a recoverable warning. The documented pattern is to return or throw the result of notFound() from beforeLoad or loader. The API reference also shows passing routeId: rootRouteId when the developer wants a resource failure to be displayed at the whole-page level rather than at the local route level.

Sources: docs/router/guide/not-found-errors.md, docs/router/api/router/notFoundFunction.md

import { createFileRoute, notFound, rootRouteId } from '@tanstack/react-router'
 
export const Route = createFileRoute('/posts/$postId')({
  loader: ({ context }) => {
    if (!context.post) {
      throw notFound()
    }
 
    if (!context.team) {
      throw notFound({ routeId: rootRouteId })
    }
  },
})

Redirects as Route Control Flow

Redirects are documented with the same return-or-throw control-flow shape as not-found errors, but they represent a different outcome: the router should navigate to another location instead of rendering an error or not-found component. The standalone redirect function accepts a required Redirect options object and returns a Redirect object unless the throw option is set to true, in which case the function throws from inside the call. Loaders and beforeLoad callbacks can also throw the returned redirect object directly, which makes authentication checks and migration gates concise.

Sources: docs/router/api/router/redirectFunction.md

The redirect API supports internal route navigation with to and external navigation with href. Internal redirects are the normal choice for app routes such as sending an unauthenticated user to /login. External redirects are useful when a loader discovers that the browser must leave the app, such as starting an authorization flow at an identity provider. The distinction is important because to participates in Router's typed routing model, while href is an absolute external destination. Both are still expressed as redirect objects used from route lifecycle callbacks.

Sources: docs/router/api/router/redirectFunction.md

File-based routes add a route-bound redirect helper. When a route is created with createFileRoute, Route.redirect automatically sets the redirect origin from that file route's path. The documented benefit is that relative redirects such as ../login or ./migrate can be validated relative to the route without manually writing a from value. Outside the route definition file, getRouteApi('/dashboard/settings').redirect gives access to the same route-bound behavior, which keeps redirects refactoring-friendly when route paths move.

Sources: docs/router/api/router/redirectFunction.md

import { createFileRoute, getRouteApi, redirect } from '@tanstack/react-router'
 
export const Route = createFileRoute('/dashboard/settings')({
  beforeLoad: ({ context }) => {
    if (!context.user) {
      throw Route.redirect({ to: '../login' })
    }
  },
})
 
const routeApi = getRouteApi('/dashboard/settings')
 
function checkAuth(user: unknown) {
  if (!user) {
    throw routeApi.redirect({ to: '../login' })
  }
}
 
function externalAuthRedirect() {
  throw redirect({ href: 'https://authprovider.com/login' })
}

Error Display Components and Catch Boundaries

Not-found and redirect objects are route lifecycle outcomes, while render errors are exceptions thrown by component children. The CatchBoundary API covers that component-level failure mode. It renders its children while there is no error, renders an error component when a child throws, and can call an optional onCatch callback with the caught error. The required getResetKey function returns a string used to declaratively reset the boundary state when that key changes, which lets route or location changes clear a previous failure without imperative cleanup code.

Sources: docs/router/api/router/catchBoundaryComponent.md

ErrorComponent is the default error UI named by the catch-boundary API. Its props are intentionally small: error, optional info containing a React component stack, and reset, a function that programmatically resets error state. The component returns a formatted error message and can toggle display of the error message with a Show Error button. The API reference states that the error message is shown by default in development, which is a useful DX default because local failures reveal stack and message context while production apps can supply custom error components.

Sources: docs/router/api/router/errorComponentComponent.md, docs/router/api/router/catchBoundaryComponent.md

import { CatchBoundary } from '@tanstack/react-router'
 
function SettingsPanel() {
  return (
    <CatchBoundary
      getResetKey={() => 'settings'}
      onCatch={(error) => console.error(error)}
    >
      <div>Settings</div>
    </CatchBoundary>
  )
}

Compact API Reference

APIInputsOutput or effectPrimary use
notFound(options?)Optional Partial<NotFoundError>Throws when options.throw is true; otherwise returns a NotFoundError objectSignal missing resources from beforeLoad or loader and trigger notFoundComponent
redirect(options)Required Redirect optionsThrows when options.throw is true; otherwise returns a Redirect objectNavigate away from a route lifecycle callback
Route.redirect(options)Redirect options on a file routeRoute-bound redirect with automatic from originType-safe relative redirects from createFileRoute files
getRouteApi(path).redirect(options)Route path plus redirect optionsRoute-bound redirect outside the route fileShared guards or helpers that need the route's redirect context
ErrorComponenterror, optional info, resetFormatted error UI with optional message displayDefault fallback UI for caught render errors
CatchBoundarygetResetKey, children, optional errorComponent, optional onCatchChildren when healthy; error component after a thrown child errorComponent-level exception isolation and reset

Sources: docs/router/api/router/notFoundFunction.md, docs/router/api/router/redirectFunction.md, docs/router/api/router/errorComponentComponent.md, docs/router/api/router/catchBoundaryComponent.md

Implementation and Design Guidance

Use not-found handling when the requested URL or resource is semantically absent, use redirects when the app can identify a better destination, and use catch boundaries when component rendering itself fails. Keeping those categories separate makes the route tree easier to reason about: notFoundComponent communicates absence, redirect objects communicate navigation replacement, and CatchBoundary communicates exception containment. This separation also prevents authentication logic from becoming a fake 404 and prevents missing records from becoming generic JavaScript errors.

Sources: docs/router/guide/not-found-errors.md, docs/router/api/router/notFoundFunction.md, docs/router/api/router/redirectFunction.md, docs/router/api/router/catchBoundaryComponent.md

For a new route, start by deciding the desired user context for failures. If a missing child should keep the parent layout, configure notFoundComponent on the nearest meaningful route and rely on fuzzy mode. If all unknown URLs should show a global page, configure root handling. In loaders, throw notFound() for absent data and throw redirect({ to: '/login' }) or Route.redirect({ to: '../login' }) for authentication or workflow redirection. Wrap independently fragile component subtrees in CatchBoundary when a render failure should not collapse the surrounding route UI.

Sources: docs/router/guide/not-found-errors.md, docs/router/api/router/notFoundFunction.md, docs/router/api/router/redirectFunction.md, docs/router/api/router/catchBoundaryComponent.md

Next Steps

After wiring the basics, test the three failure paths deliberately: visit an unmatched URL, load an existing route with a missing resource, and force a child component to throw inside a boundary. Confirm that each case renders at the intended level of the route tree and that redirects preserve the desired typed origin. Related topics to read next are authenticated routes for guard patterns, data loading for loader placement, route trees and outlets for layout composition, and the Router API reference pages for the exact route option types behind these components.