ERR_TOO_MANY_REDIRECTS: How to Find and Fix a Redirect Loop
This page isn't working. example.com redirected you too many times. ERR_TOO_MANY_REDIRECTS
Firefox calls it "The page isn't redirecting properly". Both mean the same thing: the browser followed redirects until it hit its limit (20 in Chrome and Firefox), because two or more rules keep sending it back and forth. Something says "go to B", and B says "go to A".
Step 1: trace the loop
curl shows each hop without any browser cache in the way:
curl -sIL --max-redirs 10 http://example.com/ | grep -iE "^(HTTP|location)"
HTTP/1.1 301 Moved Permanently
location: https://example.com/
HTTP/2 301
location: http://example.com/
HTTP/1.1 301 Moved Permanently
location: https://example.com/
Now you can see the circle — here, HTTP → HTTPS → HTTP. The pattern in the location lines tells you which kind of loop you have. The HTTP Status Checker shows the same chain in the browser.
The usual causes
HTTPS redirect behind a proxy or CDN
The most common loop. Your app redirects HTTP to HTTPS, but it sits behind a load balancer or CDN that talks to it over plain HTTP. Every request arrives as HTTP, so the app redirects every request — forever.
- Cloudflare: with SSL mode Flexible, Cloudflare connects to your server over HTTP. If the server redirects to HTTPS, you loop. Switch to Full (strict) and install a certificate on the origin.
- Your app behind a proxy: tell the framework to trust the proxy's
X-Forwarded-Protoheader, so it knows the original request was HTTPS. In Express,app.set("trust proxy", 1); in Django,SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https"). See X-Forwarded-For for how the forwarded headers work.
www and apex rules fighting
One layer redirects www.example.com → example.com while another redirects example.com → www.example.com — often the hosting dashboard against an nginx or app rule. Pick one canonical host and make every layer agree.
Trailing-slash rules
A framework setting adds a trailing slash (/docs → /docs/) while the server or CDN removes it. Same fix: decide on one form and remove the other rule.
Login loops
A page requires authentication and redirects to /login; /login thinks you're logged in (or itself requires auth) and redirects back. Two common roots:
- The session cookie is never stored — for example it's marked
Securebut the site runs on plain HTTP, or itsDomaindoesn't match. See Set-Cookie. - The cookie isn't sent on the request that matters — a cross-site POST back from an identity provider, blocked by
SameSite. See SameSite cookies explained.
CMS address settings
In WordPress, a mismatch between the "WordPress Address" and "Site Address" settings — http:// against https://, or www against no www — loops the same way. Make both identical and match your real canonical URL.
Step 2: rule out the browser's cache
A permanent redirect (301 or 308) can be cached by the browser indefinitely. After you fix the server, the browser may keep looping on its cached redirect. Test in a private window or with curl, and clear site data (DevTools → Application → Storage → Clear site data) for the real browser.
This is also why it's worth testing new redirects as 302 first — see 301 vs 302 vs 307 vs 308.
Quick checklist
- Trace the hops with
curl -sIL. - Find the two rules that disagree — protocol, host, slash or auth.
- Keep one rule; remove or align the other.
- Retest in a private window.