throw redirect('/login')
not redirecting but rendering errorElement
instead?I was working with React Router's data APIs and using throw redirect("/login")
in my loader
functions to protect routes. However, instead of redirecting to /login
, React Router was rendering the errorElement
for that route or showing an error response.
I found that manually setting response.body = true
after calling redirect()
made it work (got this idea from this post answer of this guy https://stackoverflow.com/a/76852081/13784221 :
import { redirect } from "react-router-dom";
export async function requireAuth() {
const isLoggedIn = false;
if (!isLoggedIn) {
const response = redirect("/login");
response.body = true; // 👈 This made it work!
throw response;
}
return null;
}
This issue is related to how React Router internally handles thrown Response
objects in loaders and actions. It distinguishes between:
Redirect responses (status
codes 3xx)
Error responses (4xx or 5xx)
And... "unexpected" responses (e.g., missing body info)
When I throw redirect("/login")
, it creates a Response
object with status = 302
and no body. Now, when you also provide an errorElement
, React Router plays safe and tries to render it unless it's very sure you're doing a proper redirect.
React Router checks for:
error instanceof Response && error.status >= 300 && error.status < 400 && error.bodyUsed
So if bodyUsed is false, it falls back to showing the errorElement.
response.body = true
Setting response.body = true
(or even response.bodyUsed = true
) tricks React Router into treating your Response
object as “used” and safe to redirect.
So this:
const response = redirect("/login");
response.body = true;
throw response;
...acts as if the redirect body has been processed, and skips rendering the errorElement
.