DEV Community

Cover image for How a cached 301 put our homepage in a redirect loop (CloudFront + WordPress)

How a cached 301 put our homepage in a redirect loop (CloudFront + WordPress)

One morning our marketing site's homepage started failing with ERR_TOO_MANY_REDIRECTS. Every other page was fine. The cause turned out to be a perfectly reasonable cache setting meeting a perfectly reasonable SEO plugin. Here's the chain, because it's an easy one to walk into.

The two reasonable settings

1. The SEO plugin strips tracking parameters. Our WordPress site (bytephase.com) uses Yoast, which can 301-redirect /?fbclid=abc or /?utm_source=x to the clean URL /. That's good for duplicate-URL hygiene.

2. The CDN ignores tracking parameters in the cache key. In CloudFront we excluded utm_*, gclid, fbclid and msclkid from the cache policy. Otherwise every ad click creates a fresh cache entry and a cache miss. Also good.

How they combine

  1. A visitor arrives at /?fbclid=abc.
  2. CloudFront drops fbclid from the cache key, so the request maps to the cache entry for /. But the origin request policy still forwards fbclid to WordPress.
  3. WordPress sees the parameter and answers 301 → /.
  4. CloudFront caches that 301… under the key for /.
  5. The next visitor requests /, gets the cached 301 → /, follows it, and gets the same 301. Loop.

The homepage was the only victim because it's where ad and social traffic lands.

Six-step diagram of a CloudFront redirect loop: tracking parameter dropped from the cache key but forwarded to WordPress, whose 301 gets cached under the homepage key

The fix

The cache key and the origin request must agree on which parameters exist. If CloudFront ignores a parameter for caching, it must also not forward it to the origin.

We switched the origin request policy from "all viewer query strings" to all except the same list the cache policy excludes:

utm_source, utm_medium, utm_campaign, utm_term,
utm_content, utm_id, gclid, fbclid, msclkid
Enter fullscreen mode Exit fullscreen mode

Now WordPress never sees fbclid, so it never issues the redirect, and nothing poisonous gets cached. Analytics still works, because GA reads the parameters client-side from the browser URL, not from the server.

Then we invalidated /*.

Two gotchas while verifying

  • Your browser caches 301s too. After the edge was fixed, Chrome kept looping from its own redirect cache. Test with a fresh profile, or fetch(url, {cache: 'reload'}), before declaring it still broken.
  • The loop can return quietly. Add a parameter to the cache-key exclusions later without adding it to the origin exclusions, and the same chain re-forms. We now keep the two lists side by side in the same change.

Takeaway

Any time a CDN normalises a request (drops parameters, headers or cookies from the cache key), ask: can the origin answer differently based on the thing I just dropped? If yes, either keep it in the key or stop forwarding it. Redirects are the worst case, because they're cacheable and they point at themselves.


We build repair shop management software at BytePhase. The marketing site is WordPress behind CloudFront, and we write up the infrastructure lessons here as we hit them.

Top comments (0)