Three days. That’s how long I stared at my screen, questioning my career choice, doubting everything I knew about coding. And the fix? One line. One stupid line that I missed a hundred times.
The Problem Started Simple
We had a bug in our payment system. Users were getting charged twice. Not always — just sometimes. Around 1 in 50 orders. My team lead handed me the ticket on a Monday morning.
“Should be quick,” he said. Famous last words.
Day 1: Going in Circles
I started by checking the payment gateway integration. Maybe their API was flaky? I added more logging. I checked webhook retries. I stared at our database queries. Nothing made sense.
The double charges happened randomly. No pattern in the logs. No error messages. The transactions went through cleanly — just twice.
Day 2: Deep in the Code
By Tuesday, I was reading our checkout code line by line. I traced every function call. I checked if users were clicking the button twice. I added a loading state to prevent double clicks. Still happening.
I started questioning everything. Maybe it was a race condition? I added locks. I checked our Redis setup. I even looked at our Nginx config.
Nothing worked. I was stuck.
Day 3: The Realization
Wednesday morning. I opened the same file for the hundredth time. And there it was — buried in a helper function I wrote two months ago.
Something like this:
async function processPayment(order) {
const existing = await checkPending(order.id);
if (!existing) {
await savePending(order.id);
await chargeUser(order);
}
}
The problem? The savePending was after the check but before the charge. If two requests came in milliseconds apart, both would pass the check (because nothing was saved yet), and both would charge.
The Fix
One line. I moved the save up:
async function processPayment(order) {
await savePending(order.id); // moved up
const existing = await checkPending(order.id);
if (!existing) {
await chargeUser(order);
}
}
If the second request tries to save, it fails because there’s already a pending record. Simple. One line change.
What I Learned
Here’s the thing — I wasn’t stupid. The bug was subtle. Race conditions are like that. But looking back, I wasted too much time looking in the wrong places.
- Don’t assume your code is fine. The most obvious place is often the last place you look.
- Add better logging earlier. I spent days adding logs in the wrong spots.
- Take breaks. I was so stuck in the problem that I couldn’t see the obvious.
Now whenever I face a weird bug, I start by questioning my recent code. The simplest explanation is usually right — and it’s usually something I wrote.
Three days for one line of code. Would do it again. That’s just debugging.
