How I Wasted My Day Debugging Redirects So You Don't Have To
Understanding stubborn redirect glitches

Search for a command to run...
Understanding stubborn redirect glitches

No comments yet. Be the first to comment.
How to store, display, and work with date and timezone data in your web applications

A look at how the scientific process can help figure out very puzzling production issues

I love puzzles. As a developer sometimes they end up on my lap and I get to play Sherlock Holmes a bit. This post is to share the learnings on how I managed to track down and solve a problem that has been plaguing us for a while: a stubbornly low cac...
While working on some improvements to the caching granularity in the Prosple platform, I found myself needing to override the cache tags being sent in a GraphQL response. This is because Drupal has a lot of cache tags, and while they are all incredib...
If you’re not a fan of stories and are just looking for a quick way to help you on your redirects debugging, then you could skip to the part about the blog post. Otherwise, continue reading.
There I was, finally almost wrapping up a task I’ve been doing for almost a month. I was tasked with upgrading our frontend codebase from Next 10 to Next 15 and React 16 to React 19. I tested everything and no bugs in sight. After weeks of headaches and new white hairs produced, I was finally confident in its stability. And so, I passed off my work to QA.
QA did their thing, and they found one bug. I looked at the bug and it was a single redirecting issue, shouldn’t be so complicated. I let out a huge sigh of relief. With all that work and possible uncertainties, only one bug was found that seemed to be simple enough. Little did I know what I was about to sign up for…
I got started right away. We had an existing legacy router and figured to look there. After a couple of trial and errors and well-placed console logs for suspect code blocks, no findings so far so I marked the legacy router itself “Clear”. Next, a file called redirect.js - a prime suspect. It had code that explicitly uses a 301 redirect, jackpot! Not even an hour in, it seems I already hit the gold mine. There were no other relevant codes even mentioning a 301 redirect in the code. Where else could it be, right? WRONG! I tested the redirect again and again, still the same thing. This was where things started to become blurry.
If not the part of the code that explicitly has 301 in it, and is called redirect.js, where should I even look? I honestly had no idea. I looked into our custom server.js entrypoint for our Next.js app, no luck with that. I tried moving away the page from our legacy router into Next’s default file-based router, nope. I tried upgrading possible related dependencies, nada! At this point, I was deep in the weeds - losing time, losing patience, and possibly losing my mind. I’ve been gaslighting myself that some things that are obviously unrelated could possibly be culprits. I mean, where else would I look? I even tried debugging our GraphQL infrastructure, and tried modifying it. In the end, I tried going back by batches in commits and testing the redirect issue in each version until I reached the version of our live production code… huh? It’s still not working? I tried in production, and even asked my teammates to try locally, it worked for them. What was happening? It all made sense earlier, nothing makes sense now.
Just as I was about to give up, I found this article named “How to Debug Browser Redirects” by Hristiyan Dodov. He quoted:
“In the absense of cache control directives that specify otherwise, a 301 redirect defaults to being cached without any expiry date.”
Suddenly, everything made sense. I wasn’t crazy. My code wasn’t broken. My tools (especially the browser) weren’t lying — they were just too helpful, in a misleading way.
It was the browser cache all along that was keeping me away from getting answers.
The best solution for my case that Dodov mentioned is using cURL in the terminal.
At first glance, it didn’t seem like anything special — just another terminal command I’d probably forget to use. But in reality, cURL ended up being the most objective, unfiltered, and browser-free way to know what was actually happening between my app and the client.
After hours of chasing false leads, I started revisiting the “obvious” fixes I had tried earlier - changing code, tweaking routes, updating configurations. I eventually confirmed the issue was related to redirect.js as I suspected, but the browser's aggressive caching prevented me from seeing my fixes work. But this time, instead of testing them in the browser (which had misled me before due to its aggressive caching of the 301 redirect), I tested using cURL:
// Command
curl -I http://localhost/profiles
// Response
HTTP/1.1 301 Moved Permanently
X-Powered-By: Express
Path=/; Max-Age=316224000
location: /profiles?default=1
Date: Wed, 23 Apr 2025 17:19:44 GMT
Connection: keep-alive
Keep-Alive: timeout=5
This command showed me the valuable information like Max-Age (The duration of the 301 cache in seconds). It helped me confirm if my fixes were working or not with confidence. The issue wasn’t my fix… it was that the browser still held onto an outdated redirect in its cache. I had solved the bug hours earlier — I just didn’t know it.
See the full redirect chain:
curl -IL https://yourdomain.com/path
Mimic a specific user agent:
curl -A "Mozilla/5.0" -I https://yourdomain.com/path
View detailed request/response activity:
curl -v https://yourdomain.com/path
What started as a simple bug ended up being a full day's journey into the quirks of 301 redirects and browser caching. The lesson? When debugging redirects, don't trust your browser alone—it might be secretly caching responses that make you question your sanity.
Remember these key takeaways:
Browser caching of 301 redirects can be extremely persistent (potentially cached indefinitely!). If possible code your redirects to include Max-Age.
Use command-line tools like cURL to see the actual HTTP responses without browser interference.
Search more information about similar issues even beforehand to avoid falling into the debugging hell like me.
If you’d like to read more information about Dodov’s approach to debugging redirects (HINT: He has other tools he uses there as well), you can check out his article here.
Happy coding, and may your redirects always take you where you expect to go!