How to Fix Redirect Loops and ERR_TOO_MANY_REDIRECTS
A step-by-step way to find the URLs that redirect to each other, and the most common causes and fixes.
A redirect loop happens when the place a redirect points to redirects you straight back, so the browser keeps following hops until it gives up. Browsers stop after a limited number of redirects (roughly twenty) and show an error instead of the page. Chrome-based browsers call it ERR_TOO_MANY_REDIRECTS; Firefox says the page is not redirecting properly. The HTTP specification expects clients to detect and break out of cyclical redirections, which is why you see an error rather than an endless spinner.
The fix is always the same in principle: find the URLs that point at each other, work out which two rules disagree, and change one of them. The work is in finding those URLs and rules.
Step 1: see the loop without a browser
A browser hides the individual hops and may add cookies and cached redirects to the picture. curl shows the raw responses. Fetch headers only, follow redirects, and stop after a few hops:
curl -sSIL --max-redirs 6 http://example.com/ | grep -iE '^(HTTP|location)'An output like the following (illustrative, not from a real site) is a loop: the second hop sends you back to the first URL.
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/
...
curl: (47) Maximum (6) redirects followedRead the Location lines in order. When a URL appears twice, everything between its two appearances is the cycle. In the example, http redirects to https and something redirects https back to http, so two rules are fighting over the protocol.
If you saved the curl output, you can paste it into the Redirect Chain Analyzer in Manual Chain mode. It reads the hops you paste, reports a loop when a URL repeats, and shows the cycle. In that mode it analyzes only your pasted text and does not request anything itself. Its URL mode requests the address from your own browser, so it is limited by what browsers allow a web page to observe, which is why curl output is often the more complete evidence.
Step 2: match the cycle to a common cause
| What the cycle looks like | Usual cause | Where to look |
|---|---|---|
| http to https and back to http | A proxy or CDN talks to your server over plain HTTP while the server redirects every HTTP request to HTTPS | Proxy or CDN SSL mode, the server's HTTPS redirect rule |
| www to non-www and back | Two layers each enforce a different preferred hostname | DNS or hosting panel redirects, server rules, application base URL |
| /page to /page/ and back | The application adds a trailing slash and the server removes it (or the reverse) | Framework routing settings, rewrite rules |
| /login to /dashboard and back | The session cookie is not accepted, so the app thinks you are signed out and sends you to login again | Cookie domain, Secure and SameSite settings, session storage |
| Same URL redirects to itself | A rewrite rule matches its own output because it has no condition to stop | RewriteRule patterns and RewriteCond lines |
HTTPS redirects behind a proxy or CDN
This is one of the most frequent causes. Your server sees the request arrive over HTTP because the proxy in front of it connects that way, so a rule that says "if the request is not HTTPS, redirect to HTTPS" fires on every request, including the ones the proxy already received over HTTPS from the visitor. Many CDN and proxy services have a mode where the connection to your origin is unencrypted; the safer fix is usually to make the origin accept HTTPS and use a mode that connects to it that way, rather than removing the redirect.
When the proxy tells the origin the original scheme in a header such as X-Forwarded-Proto, the origin rule should look at that header instead of its own connection. Only trust that header if your proxy sets it and clients cannot reach the origin directly, because otherwise anyone can send it.
# Loops: matches every request, including ones that are already HTTPS
RewriteEngine On
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
# Stops when the request is already HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Behind a proxy that sets X-Forwarded-Proto
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]Test before deploying
A mistake in .htaccess or server redirect rules can take a whole site offline. Test on a staging copy or with a temporary 302 first, and keep the previous file so you can restore it quickly. Permanent (301) redirects can be cached by browsers, so a bad one may keep misbehaving after you fix it.
Conflicting hostname or slash rules
Redirect rules often live in several places at once: the DNS or hosting provider, the web server, the framework and the CMS settings. Each one is reasonable alone. If one sends visitors to www and another sends them to the bare domain, the pair loops. List every layer that can redirect, decide the one canonical form (protocol, hostname, trailing slash), and keep the rule in a single layer where you can.
In CMS and framework settings, look for a configured site or base URL. A base URL that says http or the wrong hostname will make the application redirect to it even when the server is already enforcing something else.
Cookie and login loops
If curl without cookies reaches the page but the browser loops, suspect state. A login flow that redirects to the sign-in page whenever the session is missing will loop if the browser never keeps the session cookie. Common reasons are a cookie set for the wrong domain, a Secure cookie issued over plain HTTP, a SameSite setting that blocks the cookie in the flow you are using, or a session store that is not shared between servers. Clearing cookies for the site, or testing in a private window, is a quick way to confirm this category.
Rewrite rules that match their own output
In per-directory .htaccess files Apache can re-run the rules after a rewrite, so a rule without a stopping condition may match the URL it just produced. Add a RewriteCond that excludes the destination, anchor the pattern more precisely, and consider the END flag (Apache 2.4) when you want processing to stop entirely. The .htaccess Analyzer inspects your rules statically, without running Apache, so it can help you review them but cannot prove a loop will or will not happen on your server. The related guide on Apache rewrite rules explains the flags in more detail.
Step 3: fix one layer and test again
- Change one rule or setting at a time, so you know which change worked.
- Re-run the curl command and confirm the chain ends in a 200 response (or the intended final status).
- Check the http and https versions, with and without www, and a URL with and without a trailing slash.
- Test in a private window to rule out cached 301 redirects and stale cookies.
- When the loop is gone, collapse any remaining chain to a single hop. See the article on redirect chains for why that matters.
What not to do
- Do not disable HTTPS enforcement just to stop the loop; fix the scheme detection instead.
- Do not add a second redirect to "correct" the first. That usually extends the cycle.
- Do not test only in the browser. Cached redirects and cookies can mislead you in both directions.
- Do not forward the same URL to the homepage as a catch-all fix; it hides the problem and sends visitors to the wrong content.
Sources
- MDN Web Docs, Redirections in HTTP: https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections
- RFC 9110, HTTP Semantics, section 15.4 (Redirection 3xx): https://www.rfc-editor.org/rfc/rfc9110#section-15.4
- Apache HTTP Server documentation, mod_rewrite: https://httpd.apache.org/docs/current/mod/mod_rewrite.html
Frequently asked questions
- What does ERR_TOO_MANY_REDIRECTS mean?
- It is the error Chrome-based browsers show when a request keeps being redirected without ever reaching a page. Firefox words it as the page not redirecting properly. The cause is a cycle: URL A redirects to B, and B (directly or through more hops) redirects back to A.
- Will clearing cookies fix a redirect loop?
- Sometimes. If the loop involves a login or session cookie, a stale or blocked cookie can send the browser back and forth. If the loop also happens in curl with no cookies, the cause is in the server, proxy or application configuration instead.
- Is a redirect loop the same as a redirect chain?
- No. A chain eventually ends at a page, just with more hops than necessary. A loop never ends, so the visitor gets an error instead of a page.
- How do I see the loop without a browser?
- Run curl with -I to fetch headers only, -L to follow redirects and --max-redirs to stop after a few hops. The Location header of each response shows where the server sent you next.
Try it yourself
The tool that pairs with this guide.
Redirect Chain Analyzer
Analyze URL redirects, detect redirect chains and loops, and inspect HTTP status behavior.
.htaccess Analyzer
Analyze Apache .htaccess configuration, rewrite rules, redirects, security settings and common server issues.
Did this help you untangle your redirects?
If these free developer tools save you time, consider buying me a byte. Your support helps keep DevCraftKit free and growing.
Related articles
What Are Redirect Chains? Causes, Impact and How to Fix Them
Several hops where one would do: how redirect chains form, what they cost, and how to find and fix them.
Published
301 vs 302 vs 307 vs 308 Redirects: Which Status Code to Use
Two questions decide the code: is the move permanent, and must the request method be preserved?
Published
What Is Open Graph and How Does It Work?
The meta tags behind every link card: what Open Graph is, how platforms use it, and how a preview is built from your page.
Published