React Router reports this error when a route resolves to a component that returns something other than a React element (for example because it lacks a return value, is declared async, or falls through every branch).
React Router throws this error when it instantiates the component that a route points at and that function fails to deliver a React element or null. Instead of producing JSX, the component returned undefined, a Promise, or simply reached the end of the body without yielding anything, so the router cannot continue rendering and surfaces the message before the DOM updates. The framework derives the component either from the routes you declare inside <Routes> or from the route objects you pass to createBrowserRouter/createRoutesFromElements. After React creates the component, it immediately inspects the return value. When the value is not a valid React node, React Router halts the render tree and reports the failure, because it relies on that element to keep walking the tree and mounting nested <Outlet>s. In practice the culprit is often forgetting to return JSX inside the component, declaring the component as async (which always returns a Promise), or letting conditional guards fall through all branches. Verifying the component’s body and how it is wired into the route pair usually lets you fix the issue quickly.
React Router 6 expects the element prop to receive JSX. Do not pass the component constructor directly:
// ❌ Incorrect: element receives the component type
<Routes>
<Route path="/" element={Home} />
</Routes>
// ✅ Correct: element receives the JSX element
<Routes>
<Route path="/" element={<Home />} />
</Routes>Every branch of the component must return a valid React node or null:
const Dashboard = () => {
if (!isReady) {
return null; // ❌ This should not be left implicit
}
return (
<main>
<h1>Dashboard</h1>
</main>
);
};Marking a component as async makes it return a Promise, which React Router refuses to render. Move data fetching into loaders/useEffect or wrap a lazy import with Suspense instead:
// ❌ This returns Promise<ReactNode> and triggers the error
const Profile = async () => {
await fetchUser();
return <div>Profile</div>;
};
// ✅ Keep the component synchronous
const Profile = () => {
const user = useUser();
return <div>Profile for {user.name}</div>;
};Make sure every guard returns something instead of falling through. Explicitly return null when you need to skip rendering:
const Settings = ({ config }) => {
if (!config) {
return null; // explicit return keeps the router happy
}
if (config.disabled) {
return <DisabledNotice />;
}
return <SettingsPanel config={config} />;
};React Router validates each RouteObject.element when it resolves routes from JSX or the route array. The validation happens inside createRoutesFromChildren/createRoutesFromElements before any nested <Outlet> renders, which is why the error shows up immediately. If you still need to fetch data before rendering, use loaders (createBrowserRouter + loader) or React.lazy with Suspense; both keep your component synchronous while React Router waits for the data and then renders a valid element.
Also make sure you export the component you intend to render (default or named) so that the import is not undefined. An undefined component will also produce this error even if everything else is correct.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite