dgtlmoon/changedetection.io · error · Exception

Too many redirects

Error message

Too many redirects

What it means

The requests fetcher caps manual redirect following; when the loop exits without a non-redirect response (redirect chain exceeds the attempt limit) it raises 'Too many redirects'.

Source

Thrown at changedetectionio/content_fetchers/requests.py:126

            current_url = url
            for _ in range(10):
                if not r.is_redirect:
                    break
                location = r.headers.get('Location', '')
                redirect_url = urljoin(current_url, location)
                if not allow_iana_restricted:
                    if is_url_private_or_parser_confused(redirect_url):
                        raise Exception(f"Redirect blocked: '{redirect_url}' resolves to a private/reserved IP address "
                                        f"or contains a parser-differential payload.")
                current_url = redirect_url
                r = session.request('GET', redirect_url,
                                    headers=request_headers,
                                    timeout=timeout,
                                    proxies=proxies,
                                    verify=False,
                                    allow_redirects=False)
            else:
                raise Exception("Too many redirects")

        except Exception as e:
            msg = str(e)
            if proxies and 'SOCKSHTTPSConnectionPool' in msg:
                msg = f"Proxy connection failed? {msg}"
            raise Exception(msg) from e

        # If the response did not tell us what encoding format to expect, Then use chardet to override what `requests` thinks.
        # For example - some sites don't tell us it's utf-8, but return utf-8 content
        # This seems to not occur when using webdriver/selenium, it seems to detect the text encoding more reliably.
        # https://github.com/psf/requests/issues/1604 good info about requests encoding detection
        if not is_binary:
            # Don't run this for PDF (and requests identified as binary) takes a _long_ time
            if not r.headers.get('content-type') or not 'charset=' in r.headers.get('content-type'):
                # For XML/RSS feeds, check the XML declaration for encoding attribute
                # This is more reliable than chardet which can misdetect UTF-8 as MacRoman
                content_type = r.headers.get('content-type', '').lower()
                if 'xml' in content_type or 'rss' in content_type:

View on GitHub (pinned to 5d9c7c6da7)

Solutions

  1. Trace the chain: curl -IL <url> and look for the loop point
  2. Add required cookies/headers or a User-Agent the site expects
  3. If the loop is on the server side, watch the final destination URL directly
Defensive patterns

Strategy: retry

Validate before calling

import requests
r = requests.get(url, allow_redirects=False, timeout=10)
seen = set()
while r.is_redirect:
    nxt = r.headers['Location']
    if nxt in seen:
        raise ConfigError('redirect loop detected — fix watch URL')
    seen.add(nxt)
    r = requests.get(nxt, allow_redirects=False, timeout=10)

Try / catch

try:
    fetcher.run()
except Exception as e:
    if 'Too many redirects' in str(e):
        trace_chain(url)  # find the loop and update watch to final URL

Prevention

When it happens

Trigger: URL whose redirect chain never terminates — A→B→A loops, cookie-less client stuck on a consent/redirect page, or server always answering 30x.

Common situations: Site requiring cookies/headers the fetcher lacks so it loops on the same redirect; misconfigured server; intentional redirect loop.

Related errors


AI-assisted analysis of dgtlmoon/changedetection.io@5d9c7c6da7 (2026-08-27). Data as JSON: /api/errors/952816f6820ef2ae. Report an issue: GitHub.