devkult_
tools29converters34
home/blog/err-too-many-redirects
httpdebuggingnginx

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-Proto header, 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 Secure but the site runs on plain HTTP, or its Domain doesn'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

  1. Trace the hops with curl -sIL.
  2. Find the two rules that disagree — protocol, host, slash or auth.
  3. Keep one rule; remove or align the other.
  4. Retest in a private window.
More from the blog