Some of the most useful JavaScript lessons seem to come from bugs that initially look completely harmless.
Maybe a button works twice instead of once, an event listener gets attached multiple times, a value is unexpectedly undefined, or something behaves differently after navigating back to a page.
I’m curious about the small bugs that other developers have encountered that changed the way they write JavaScript.
What’s one bug you remember thinking:
“How can this possibly be happening?”
And what did you eventually discover was causing it?
Beginner mistakes are welcome too. Sometimes those are the most useful ones for other developers to learn from.
One bug that taught me a lot was an event handler firing multiple times even though the code looked perfectly normal. I eventually found that the event listener was being added every time a component or section was initialized, without removing the previous listener.
It was a good reminder that JavaScript bugs aren’t always caused by complicated logic. Sometimes the code is correct in isolation, but the way and how often it runs creates the problem. Since then, I’ve become much more careful about initialization, event listeners, and cleanup—especially in dynamic pages and single-page applications.
That duplicate-listener one is painfully familiar. The code reads fine, the button looks fine, and then it fires twice and you start questioning everything except the setup code.
Mine in the same family was a form that submitted twice, but only sometimes. Turned out the init function ran again every time a section was re-rendered, so the listener stacked up. Logging how many times the handler ran was what finally gave it away — I kept looking for a logic bug when the real problem was just how often the setup ran.
The lesson that stuck with me was to treat listener setup like a resource: if you add it, you need a clear place where it gets removed. These days I try to make init idempotent, or at least make it obvious when it’s running more than once.
The form-submitting-twice detail stands out because of the “only sometimes” part. That kind of intermittent bug is the worst to chase, since a successful submission makes you think it’s fixed. Logging how many times the handler ran seems like the simplest diagnostic that actually pinpoints the setup code rather than the logic. I also like the idea of treating listener setup as a resource with a clear removal point. Making init idempotent is a practical way to keep re-renders from quietly stacking behavior.
The “only sometimes” detail really is what makes that class of bug so draining. In the form case, a working submission looks identical to a fixed one, so you stop digging at exactly the wrong moment. I like your point about logging handler invocations: it tests the setup path directly instead of re-reading the logic that was probably never wrong. Treating init as idempotent also fits situations where re-rendering is unpredictable. One small addition — logging a counter or timestamp when the setup runs, not only when the handler fires, can show whether the stacking starts at first render or only after a refresh.