Skip to content

React Tutorial Routing and Application Structure

Not Found Pages and Route Errors in React Router

Lesson 109 of 156 3 min read By Deepak Paswan Updated Oct 10, 2026

Full-project lesson · needs Node.js, npm and real project files, so it does not run in the in-page playground.

Users mistype addresses, follow old links and open pages that no longer exist. A good app shows a clear not found page with a way back, instead of a blank screen.

The catch-all route

A route with path="*" matches any URL that no other route matched:

src/App.jsx
JSX
import { Routes, Route, Link, useParams } from 'react-router'

const PRODUCTS = [{ id: 1, name: 'Keyboard' }, { id: 2, name: 'Mouse' }]

function Home() {
  return <h1>Home page</h1>
}

function ProductDetail() {
  const { id } = useParams()
  const product = PRODUCTS.find((p) => String(p.id) === id)
  // A valid route, but no such product: show the same not-found page
  if (!product) return <NotFound />
  return <h1>Product {product.id}: {product.name}</h1>
}

function NotFound() {
  return (
    <div role="alert">
      <h1>Page not found</h1>
      <p>The page you are looking for does not exist or has moved.</p>
      <Link to="/">Go to the home page</Link>
    </div>
  )
}

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/products/:id" element={<ProductDetail />} />
      <Route path="*" element={<NotFound />} />
    </Routes>
  )
}

export default App

Tested in a real browser: an unknown URL shows the 404 page, the link takes the user home, and /products/abc (a route that matches, but with no such product) shows the same page.

Two kinds of “not found”

  1. No route matches the URL (a typo, an old link). The * route handles it.
  2. The route matches but the data does not exist (/products/9999). Your component must check and show the not-found UI, as ProductDetail does. Do not leave users on an empty page, and do not crash on undefined.

What makes a good 404 page

  • Say plainly that the page was not found.
  • Keep the site navigation so users can recover; render the 404 inside your normal layout (put the * route inside the layout route).
  • Offer useful ways out: a link home, search, popular pages.
  • Do not blame the user; avoid jokes that hide the message.

Errors during loading or rendering

In data mode (createBrowserRouter), routes can name an error screen. React Router renders it if a loader or a component in that route throws:

App.jsx
JSX
import { useRouteError, isRouteErrorResponse, Link } from 'react-router'

function RouteError() {
  const error = useRouteError()

  if (isRouteErrorResponse(error) && error.status === 404) {
    return <h1>Page not found</h1>
  }
  return (
    <div role="alert">
      <h1>Something went wrong</h1>
      <p>Please try again, or go back.</p>
      <Link to="/">Home</Link>
    </div>
  )
}

const router = createBrowserRouter([
  { path: '/', Component: Layout, ErrorBoundary: RouteError, children: [ /* ... */ ] },
])

A loader can signal a missing item by throwing a response, which the error screen turns into a 404 message (see Route Loaders and Lazy Routes). Unmatched URLs in data mode also reach the nearest error screen as a 404 response.

React Router also supports errorElement (an element instead of a component). For crashes in any other component, add an error boundary (Error Boundaries).

The 404 status problem in single-page apps

A static single-page app serves index.html with HTTP status 200 for every URL, even a page that does not exist. To a search engine this looks like a real page, which is called a soft 404. Real “not found” status codes need the server to know your routes, which is something frameworks with server rendering do. For a client-side app you can reduce the harm by:

  • adding a <meta name="robots" content="noindex"> tag on your not-found page (React 19 can render <meta> from the component),
  • keeping the list of valid URLs in a sitemap,
  • and using a framework if search visibility of many dynamic pages is important (Client-Side React vs React Frameworks).

Redirects for moved pages

When you rename a URL, keep the old one working with a redirect (<Navigate replace> as in Navigation), or better, configure a real HTTP 301 on your server so search engines learn the new address.

Key points

  • <Route path="*"> catches unmatched URLs; show a clear page with a way back.
  • Also handle routes that match but whose data is missing.
  • In data mode, ErrorBoundary / errorElement plus useRouteError handle route errors; remember soft 404s in client-only apps.