useNavigate() may be used only in the context of a <Router>
A component used React Router’s navigation outside the router, so it had no route information to work with.
Also appears as
- useLocation() may be used only in the context of a <Router> component.
- useHref() may be used only in the context of a <Router> component.
Prompt to fix it
My app crashes with "useNavigate() may be used only in the context of a <Router> component." Find where the router is set up (BrowserRouter or RouterProvider) and every component that calls useNavigate or useLocation, or renders <Link>, outside it. Move the router up, usually into main.tsx around <App />, or move those components into a layout route, so all of them are inside it. Wrap tests and stories in MemoryRouter. Check that react-router and react-router-dom aren’t installed at different major versions. Don’t replace navigation with window.location to get around it.
Paste into Layerwise or any AI coding tool.
What it means
React Router keeps the current URL and its navigation tools in a context: shared data that only components inside <BrowserRouter> or <RouterProvider> can reach. useNavigate, useLocation, and <Link> all read from it. When a component calls one of them from outside that wrapper, there is nothing to read, and React Router throws. A <Link> outside the router reports it as useHref().
The component calling the hook usually sits above the router in the tree. A common shape: App calls useNavigate() and also renders <BrowserRouter> in its own JSX. The router only covers what it wraps, so App itself is outside it.
If the component is clearly inside the router, check for two copies of React Router. A project that mixes react-router-dom 6 with react-router 7 gets two separate contexts, so hooks from one package can’t see the router from the other.
Common causes
- The component that renders
<BrowserRouter>also callsuseNavigate(), so the hook runs above the router. - A header, toast, or provider that uses
<Link>oruseNavigate()is rendered next to the router inmain.tsxinstead of inside it. - A test or Storybook story renders the component without a router around it.
- The app imports from
react-router-domandreact-routerat different major versions.
How to fix it
- Find where the router is set up, usually
<BrowserRouter>or<RouterProvider>inmain.tsxorApp.tsx. - Move the router up so it wraps every component that uses router hooks or
<Link>. IfAppneedsuseNavigate(), wrap<App />inmain.tsx. - With
createBrowserRouter, render shared layout pieces like headers inside a layout route instead of outside<RouterProvider>. - In tests and stories, wrap the component in
<MemoryRouter>. - Run
npm ls react-router react-router-domand import everything from one package at one major version.
Example fix
// src/main.tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router';
import App from './App';
createRoot(document.getElementById('root')!).render(
<StrictMode>
{/* Wrapping App here lets App itself call useNavigate(). */}
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>
);Related errors
All errorsInvalid hook call
A hook such as useState ran somewhere React can’t track it, or the app loaded two copies of React that don’t know about each other.
404 on page refresh
Your single-page app works from the home page, but the host has no file for deeper URLs, so reloads and shared links hit a 404.
Element type is invalid
A JSX tag pointed at undefined or an object instead of a component, almost always because an import doesn’t match how the file exports it.
Hydration failed
The HTML the server sent didn’t match what React rendered first in the browser, so React threw that part away and rebuilt it on the client.
Build with an agent that checks its work
The Layerwise agent clicks through the live preview and reads the console, so it catches errors before you do.