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 = trueSetting 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.