Code failures (more commonly known as bugs) are situations in which the code we have written does not perform the function it should. A syntax error (some extra or missing character), a data type mismatch, or the execution of unwanted code are just a few of the many reasons that can cause our code to not work as expected.
There are methodologies (for example, TDD) that drastically reduce the bugs we introduce into our code, but what happens when there are bugs that alter their behavior while we are debugging them? Let me introduce you to heisenbugs.
What Is a Heisenbug?#
The term heisenbug was coined in honor of physicist Werner Heisenberg and is defined as follows:
A heisenbug is a software bug that seems to disappear or alter its behavior when one attempts to study it.
The similarity with the observer effect in quantum mechanics is what justifies the name; the observer effect is the theory that observing a situation or phenomenon necessarily changes it.
The term is not new, and was already used by Jim Gray in a paper on software failures in 1985, and by Jonathan Clark and Zhahai Stewart in the comp.risks mailing list in 1986.
How Can a Heisenbug Occur?#
A heisenbug typically occurs when trying to change values while debugging a program. By changing the memory addresses of variables and continuing execution, the code no longer points to the previous addresses but to the new ones. Consequently the code does not reproduce the failure we are trying to resolve.
A very typical failure is one that occurs when running a program compiled with an optimizing compiler, but which cannot then be reproduced when the program is compiled without optimization. When debugging, values that are normally kept in registers in an optimized program are moved to main memory. This can affect, for example, the result of a floating point comparison since the value in memory could have greater precision and range than the one in the register.
Other common cases are the use of uninitialized variables, which may change their address and/or value during the start of debugging, or following an invalid pointer, which when debugging may point to a different address than when not debugging.
In fact, watchers and other interfaces that debuggers typically provide may add additional code (such as functions for accessing properties) that run invisibly and could introduce changes in the state of our program.
Time can also be a factor that introduces heisenbugs, particularly in multi-threaded applications. Running a program under a debugger can change the execution timing of a program compared to a normal run. Bugs related to race conditions may not occur if the program runs more slowly when using a debugger.
Example#
An example of a heisenbug was posted on StackOverflow in 2015. The code calculated the area between two curves using a do-while structure (difficult to debug manually using breakpoints). To make debugging more comfortable, the programmer added a line that printed the calculated value to the screen; however, if this line was removed the loop ran infinitely despite being a simple print statement.
The problem was that if the print statement was present, the comparison was done in CPU registers (stored as double) and the comparison never evaluated to true, causing the infinite loop. However, when the value was printed, the compiler decided to move this result to main memory where its value was truncated, and so the code executed correctly since the stop condition was eventually met.
How to Resolve Them?#
Heisenbugs are difficult both to identify and to fix. In fact, attempting to fix one can cause even more chaotic behavior in the system. Due to their changing nature they are difficult to predict and analyze during debugging.

There are programs like Jinx Debugger for debugging and identifying these types of bugs, but there is no 100% effective way to solve them. Microsoft also has a tool called CHESS for debugging this type of error; the last publications date from 2010 so I doubt it is still active.
For now, nothing similar has ever happened to me. From what I have read it seems more typical of compiled languages, but who knows — there is still a lot of development left to do...
