sfw/fix
trailing-slash loop high

Trailing-Slash Redirect Loop

Two normalization rules disagree on the trailing slash, so /page and /page/ bounce back and forth forever.

What you see

This page isn't working
example.com redirected you too many times.
ERR_TOO_MANY_REDIRECTS

What’s actually happening

The browser shows ERR_TOO_MANY_REDIRECTS and never paints. curl -IL stops with 'Maximum (50) redirects followed' and the trace flips between 301 /page -> /page/ and 301 /page/ -> /page. Often only some routes loop while the homepage loads fine, which makes it look intermittent.

Common causes

  • Framework and server disagree: Next.js trailingSlash:false strips the slash while an Nginx 'rewrite ^([^.]*[^/])$ $1/ permanent' adds it back.
  • A CDN rule (Cloudflare Bulk Redirects, an edge 'always add trailing slash' Page Rule) fights the origin's canonical handling.
  • WordPress canonical_redirect() appends a slash to a path that .htaccess or a plugin just removed.
  • Static host quirk: S3 + CloudFront treats /dir and /dir/ as different keys and one rule normalizes the opposite way.
  • A reverse proxy strips the slash before forwarding, then the app's router re-adds it on the response.

How to fix it

  1. Find both ends of the loopRun curl -sIL https://example.com/page and read the Location header on each hop. You'll see one layer sending to /page and another to /page/. Note which component emits each 301 (server header, Via, CF-Ray).
  2. Pick one canonical form and disable the other ruleDecide slash or no-slash, then turn off the competing rule. If Next.js owns it (trailingSlash in next.config.js), delete the Nginx rewrite/CDN Page Rule. Don't enforce the same policy in two places.
  3. Move enforcement to the outermost layer onlyLet the CDN or front proxy normalize once and have the origin accept whatever it receives. Configure the backend to serve both /page and /page/ with 200 instead of redirecting.
  4. Clear cached redirects before retesting301s are cached hard by browsers and CDNs. Purge the CDN path and test in a fresh private window (or curl with no cache) so you're not chasing a stale 301.

Stop it recurring

Enforce slash policy in exactly one layer and assert it with a curl redirect-trace check in CI.

Related errors