Resource URL Redirects to Itself: How to Fix It

No Comments
TL;DR

A CSS, JS, or image URL that redirects back to its own address is stuck in an infinite loop and never loads, so find the conflicting redirect rule (usually a http to https rewrite fighting a proxy or a second rule) and make the resource return a clean 200.

What this check flags

Crawlers like Sitebulb raise the hint "Page resource URL redirects back to itself" when a resource referenced by one of your pages, such as a stylesheet, a script, a font, or an image, responds with a 301 or 302 redirect whose Location header points to the exact same URL that was just requested. The request goes to URL A, the server says "go to URL A," the client obeys, and the cycle repeats until the browser gives up and throws ERR_TOO_MANY_REDIRECTS.

This is worse than an ordinary redirected resource. A normal redirect at least ends at a working file, costing only an extra round trip. A self loop never resolves at all. The resource fails to load entirely, for every visitor and every bot, on every page that references it.

Why it matters

The consequences depend on what kind of resource is trapped in the loop:

Missing CSS breaks rendering. If a looping URL is a stylesheet, the page displays unstyled or partially styled. Layout shifts, invisible navigation, and unreadable text are all on the table.

Missing JS breaks functionality. Menus that do not open, forms that do not submit, sliders and lazy loaded images that never appear. If the script also injects content, that content simply does not exist.

Googlebot renders the page broken. Google renders pages with the resources it can fetch. A looping CSS or JS file means Google evaluates a degraded version of your page, which can affect how it understands layout, mobile friendliness, and content that depends on script execution. The failed fetches also burn crawl requests for zero return.

Root causes

Conflicting http to https and https to http rules

The classic case. One layer forces HTTPS while another forces HTTP, or two rewrite rules in the same .htaccess file send the request back and forth between two forms of the same URL. The same tug of war happens with www versus non www rules pointing at each other. To the crawler, each hop lands on what is effectively the same address.

Proxy or CDN SSL mode mismatch (Cloudflare Flexible SSL)

With Cloudflare set to Flexible SSL, visitors connect to Cloudflare over HTTPS, but Cloudflare fetches from your origin over plain HTTP. If your origin then redirects HTTP to HTTPS, Cloudflare follows it, downgrades to HTTP again on the next fetch, and the loop closes. Because the origin never sees the HTTPS connection, it keeps issuing the same redirect forever. Cloudflare documents this as the textbook cause of ERR_TOO_MANY_REDIRECTS.

Case and trailing slash rewrite conflicts

A rule that lowercases URLs colliding with one that restores a canonical mixed case path, or a rule that strips trailing slashes fighting one that adds them, produces the same self loop. Resource URLs generated by plugins and build tools are common victims because their paths often contain uppercase characters or version suffixes the rules were never tested against.

How to diagnose it

Take a looping URL from the audit report and request it directly with curl, without following redirects, so you can read the Location header yourself:

curl -I https://example.com/wp-content/themes/site/style.css

HTTP/1.1 301 Moved Permanently
Location: https://example.com/wp-content/themes/site/style.css

If the Location header matches the URL you requested, you have confirmed the loop. Now repeat the request against the origin server directly, bypassing the CDN, and also test the http:// version. Comparing those three responses tells you which layer is issuing the redirect: the CDN edge, the web server config, or the application.

How to fix it, per cause

Fix conflicting rewrite rules

Keep exactly one HTTPS redirect, with a condition that stops it firing when the request is already secure. A looping rule versus a fixed one:

# LOOPS: no condition, fires on every request including HTTPS
RewriteRule ^(.*)$ https://example.com/$1 [L,R=301]

# FIXED: only redirects when the request is not already HTTPS
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://example.com/$1 [L,R=301]

Then audit every layer that can redirect: .htaccess, the server vhost, your hosting control panel, and any WordPress SSL or redirection plugin. Delete the duplicates so a single rule owns the job.

Fix the Cloudflare Flexible SSL loop

Install a valid certificate on the origin (Cloudflare Origin CA certificates are free) and switch the SSL/TLS mode from Flexible to Full (Strict). Cloudflare then talks to your origin over HTTPS, the origin stops issuing its redirect, and the loop disappears. Purge the Cloudflare cache and your browser cache after the change, since cached 301s can keep the symptom alive.

Fix case and trailing slash conflicts

Exclude resource paths from cosmetic URL rewrites. Lowercasing and slash normalization are for page URLs; add a condition that skips requests for static file extensions or your assets directories, or simply update the references to use the canonical form so no redirect is needed at all.

Common mistakes

Fixing the rule but not purging caches, so stale 301s keep looping for returning visitors. Testing only the homepage when the loop only affects certain asset paths. Switching Cloudflare to Full (Strict) without a valid origin certificate, which swaps the loop for a 526 error. And forgetting that 301s are cached aggressively by browsers, so always retest in a private window.

FAQ

Q: The page looks fine in my browser. Is this still a problem?

A: Possibly yes. Your browser may be using a cached copy of the resource from before the loop appeared. New visitors and crawlers fetch it fresh, hit the loop, and get the broken version. Test in a private window or with curl.

Q: Should I just remove the reference to the looping resource?

A: Only if the resource is genuinely obsolete. If pages still need it, the right fix is to make the URL return a 200 again. If it is dead weight, remove every reference to it and confirm the pages still render correctly afterwards.

Q: Why does the loop only affect some files and not the whole site?

A: Because the conflicting rule only matches certain patterns, such as paths with uppercase letters, missing trailing slashes, or a specific directory. That selectivity is a strong clue: compare a looping URL with a healthy one and the difference usually points straight at the guilty rewrite condition.

Need a full technical audit?

SEO ProCheck runs deep crawls that catch issues like this across your whole site.

Get in touch

Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.

About SEO ProCheck

Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.

Work With Me

Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.

Subscribe to our newsletter!

More from our blog