Skip to content
CV
Back to writing
Three days. One trailing slash.

Three days. One trailing slash.

August 18, 20266 min read1,149 words
Share

I want to tell you about the dumbest week I've had as a developer, mostly because I think the lesson in it is the one thing I'd hand to someone starting out.

A request was failing. 404. The endpoint existed, I could hit it from the terminal, and the code calling it looked fine. Should have been an afternoon.

It took three days.

I want to be clear about how those three days were spent, because it wasn't three days of careful analysis. Day one I decided it was an auth problem, because the last time something 404'd on me it had actually been a permissions thing wearing a costume. So I went through the token flow. Twice. Day two I decided the client library was at fault, downgraded it, upgraded it, read its changelog like scripture. Somewhere in there I deleted node_modules, which I know does nothing, and which I did anyway, the way you press the elevator button that's already lit.

Day three a colleague looked at my screen for about four seconds and said "why are there two slashes."

https://api.example.com//v1/users

The base URL in my env file ended in a slash. The client added one too. Two slashes, no route match, generic 404.

Here's the part that still bugs me. That URL was in the very first error I saw, on Monday morning. I had looked directly at it. I just hadn't read it, because by the time my eyes hit the screen my brain was already two steps ahead, halfway through a theory about expired tokens.

The problem wasn't that I was bad at debugging

It's that I was guessing, and guessing feels almost exactly like working.

The loop goes: something breaks, you get a hunch, you change something, you re-run. Still broken. New hunch, new change, re-run. Your hands are busy, files are changing, and it feels like momentum. But you're pulling causes out of a hat, and you have no idea how big the hat is. Maybe your next guess is the right one. Maybe there are six hundred more. There's no way to tell, and that not-knowing is what makes hard bugs so draining. It's not the difficulty. It's that they're open-ended.

And every blind change leaves residue. By Tuesday afternoon I'd touched so many unrelated things that I couldn't have described the original broken state if you'd asked me. I wasn't chasing one bug anymore. I was chasing one bug plus about a dozen I'd introduced myself.

What I do now instead

The change wasn't getting smarter. It was making myself go slower in one specific way: every move I make has to eliminate something. I don't have to be right. I just have to shrink the list.

Get it to break on command first. Same steps, same failure, every time. I used to skip this because it felt like admin work. It isn't. If a bug only shows up sometimes, you can't test a fix against it — you'll change something, watch it pass once, call it done, and meet the same bug in production on a Friday. When it's intermittent, the first job isn't fixing it. It's finding the condition that turns "sometimes" into "always."

Read the whole error. Not the top line. The whole thing, including the file paths, including the values. Out loud if it's a bad one. Stack traces are ugly enough that we've all trained ourselves to skim them, and skimming is exactly how you miss that the failure is happening in a different service than the one you've been staring at all morning. My two slashes were in the error on day one. They were just sitting there.

Cut the system in half instead of scanning it. Once you know roughly where it blows up, don't read code line by line hoping something looks suspicious. Pick a point halfway between "definitely fine" and "definitely broken" and print the value there. Is it what you expect? Then the problem is downstream. Not what you expect? Upstream. Either way you've just written off half the code in about thirty seconds, and you didn't need a theory to do it. Do that five or six times and you're standing on the bug. It's binary search, and like binary search it doesn't care how big the haystack is, only how many times you'll halve it.

One change at a time when you're close. I know the temptation. You've got three ideas, you're tired, you change all three, it works. Now what? You don't know which one did it. That's not a fixed bug, that's a bug out on bail. Change one thing, re-run, revert if it did nothing. It's tedious for about four minutes and then it saves you a day.

Don't close it until you can say why. "Removing the slash fixed it" isn't an explanation, it's a description. The explanation is: the base URL ended in a slash, the client prepends one, the router got a path it had no match for and fell through to a generic 404. That version is worth keeping. In six months I won't remember a trailing slash, but I will remember to check whether two pieces of code are both adding the same separator, and that's a whole family of bugs, not one.

That last step is also the cheapest way to make yourself useful to everyone around you. Put it in the PR description. Put it in the ticket. It costs you two sentences and saves someone else an afternoon.

Honestly, it's not that the bugs got easier

I still hit stupid ones constantly. That doesn't stop, and I've made peace with it — the week nothing surprises me is probably the week I've stopped building anything worth building.

What changed is that the bad days have edges now. They used to be open-ended. A hard bug could cost me a morning or it could cost me most of a week, and I couldn't tell which one I was in until it was over. That's the part that wore me down, more than the actual work.

Now, even four hours in with no answer, I know the list is shorter than it was at hour one. Something's been ruled out. That's usually enough to keep going without the low hum of panic underneath.

If you're early in this and every bug feels like it came out of nowhere with a knife, that's not a verdict on you. Nobody hands you a method for this. Somehow it's assumed you'll absorb it, and mostly you absorb it by wasting three days on a trailing slash.

So: get it to break reliably. Read the whole error. Cut the space in half. One change at a time. Say why before you close it.

Stop guessing faster.


If you've got a three-day bug with a one-line fix, tell me. I collect these. It helps.