01 Overview
A bug that will not reproduce is one of the most frustrating artifacts in software testing. You saw it happen. You have a screenshot, a log line, or a memory of the exact moment the interface froze or the data went sideways. But when you try again, the system behaves perfectly. The report sits in the queue, and everyone involved feels the same quiet tension: is this real, or was it a ghost? The answer almost always lies in what changed between the moment it failed and the moment you tried again. That is why the most valuable thing you can log is not just what you did, but what was different about the environment, the data, the timing, or the sequence of actions.
This article is about the craft of capturing those differences. It is not about blaming anyone or proving that a bug exists. It is about turning a frustrating non-reproducible observation into a useful record that someone else can act on. When you log what you changed, you are not admitting defeat. You are narrowing the search space for everyone who comes after you. The goal is to leave a trail that a teammate can follow, even if they never see the failure themselves. That trail is the difference between a closed ticket and a fixed defect.
02 What the report is actually claiming
When someone files a bug report, they are making a claim about the world: under certain conditions, the system did something it should not have done. The claim has three parts, whether or not the reporter realizes it. First, there is an expected behavior, which comes from a specification, a design, a user expectation, or a previous version. Second, there is an observed behavior, which is what actually happened. Third, there is a set of conditions under which the observed behavior occurred. A non-reproducible bug is usually a report where the third part is incomplete or wrong. The expected and observed behaviors are clear, but the conditions are fuzzy.
Your job as a tester or engineer is not to argue about whether the bug is real. Your job is to clarify the conditions. That means asking questions like: what was the exact state of the system before the failure? What data was loaded? What other actions had just happened? What was the timing relative to other events? When you log what you changed, you are essentially documenting the conditions you have ruled out. Each change you record is a boundary. Over time, those boundaries shrink the space where the bug can hide. Even if you never reproduce it, the next person has a map of where not to look. That map is the real deliverable of a non-reproducible investigation.
03 Severity versus priority
Severity is about damage. Priority is about scheduling. A bug that corrupts user data has high severity even if it only happens once a month. A bug that misspells a label on a settings page has low severity even if it happens every time. When a bug will not reproduce, both severity and priority become harder to assign, because you cannot measure the damage or estimate the fix. The temptation is to mark it low priority and move on. That is sometimes correct, but it should be a deliberate choice, not a reflex. The question is not whether the bug is annoying to investigate. The question is what happens if it ships unfixed.
A non-reproducible defect that touches payment flows, authentication, or data integrity deserves a higher priority than its reproducibility would suggest. You may not be able to fix it yet, but you can add logging, monitoring, or defensive checks that turn a silent failure into a loud one. That is a legitimate triage outcome. Conversely, a non-reproducible cosmetic glitch can sit in the backlog for a long time without much risk. The key is to separate the two conversations. Severity asks what could go wrong. Priority asks when we will spend time on it. Logging what you changed helps both conversations, because it gives the team evidence to argue about impact instead of guessing.
04 Writing steps someone else can follow
The classic reproduction recipe is a numbered list of actions. When a bug will not reproduce, that list is not enough. You need a second list: the variables you changed while trying to reproduce it. Write both lists in plain language, and be specific about the starting state. Instead of saying you opened the app, say you launched it from a cold start with no prior session. Instead of saying you clicked submit, say you submitted the form with a valid email and an empty phone field. The goal is to remove ambiguity, not to write a novel. A teammate should be able to read your steps and know exactly what to do, including what not to do.
The change log is where the real value lives. Record every difference between your first attempt and your later attempts. Did you use a different browser? A different user account? A different network? Did you wait longer between actions? Did you have other tabs open? Did you run the same test on a different machine? Write down what you changed and what happened as a result. If changing one thing made the bug disappear, that is a clue. If changing ten things made no difference, that is also a clue. The point is not to find the answer immediately. The point is to leave a record that someone else can extend. A good non-reproducible report reads like a lab notebook, not a complaint.
05 Running the triage queue
Triage is a routing decision, not a verdict. When a non-reproducible bug reaches the queue, the team has four realistic options. First, ask for more information and keep the report open in a needs-information state. Second, accept it as a known intermittent issue and attach monitoring or logging to catch it in the wild. Third, close it as cannot reproduce, with a note that explains what was tried and what would be needed to reopen it. Fourth, escalate it if the affected area is sensitive enough that even a rare failure is unacceptable. None of these options is inherently wrong. The wrong move is to let the report sit in limbo without a decision, because that erodes trust in the process.
A good triage meeting treats the change log as the primary artifact. The question is not whether the bug is real. The question is whether the team has enough evidence to act. If the answer is no, the next question is what evidence would change that. Maybe you need a longer soak test. Maybe you need a specific data set. Maybe you need to instrument the code and wait for a production occurrence. Assign an owner to that evidence-gathering task, even if the owner is the original reporter. The goal is to turn an open question into a bounded investigation. When the investigation concludes, the report should move to a clear status: confirmed, deferred, or closed with a documented rationale. That clarity is what keeps the queue healthy.
06 When a defect comes back
A defect that returns after being closed is a special kind of signal. It usually means one of three things. Either the original fix was incomplete, or the environment changed in a way that reintroduced the conditions, or the bug was never truly fixed and was only masked by a temporary workaround. When you see a recurrence, resist the urge to simply reopen the old ticket with a terse comment. Instead, treat it as a new investigation with the old report as background. Compare the new conditions to the old change log. What is different this time? What is the same? If the old report said the bug only appeared on a specific device, and now it appears everywhere, that is a major clue. If the old report said it only happened after a long session, and now it happens immediately, that is another clue.
The change log from the original investigation becomes a baseline. You can add to it, correct it, or contradict it, but you should always reference it. This is how teams build institutional memory. A defect that comes back is not a failure of the process. It is an opportunity to refine the reproduction recipe and tighten the fix. The worst outcome is a cycle of open, close, reopen, close, where nobody learns anything. The best outcome is a documented pattern that leads to a permanent fix or a deliberate decision to accept the risk. Either way, the record of what you changed is what makes the difference.
07 Frequently asked questions
How long should I keep trying to reproduce a bug before I log it as non-reproducible? There is no universal timer, but a useful rule is to stop when you have exhausted the obvious variables and your change log is detailed enough that a teammate could pick up where you left off. If you find yourself repeating the same attempts without new information, it is time to write up what you have and move on. The report is not a failure. It is a snapshot of an investigation.
What if my change log is messy or incomplete? That is normal. The goal is not perfection. The goal is honesty about what you tried and what you observed. Even a partial log is better than no log, because it prevents the next person from repeating your dead ends. Write down what you remember, label it as incomplete, and note what you would try next if you had more time.
Should I include screenshots or logs in a non-reproducible report? Yes, if you have them. A screenshot of the failure, a stack trace, a network log, or a console error can be more valuable than a dozen paragraphs of description. Attach what you have and explain what it shows. If you have nothing, say so. The absence of evidence is itself a useful data point.
Who decides when to close a non-reproducible bug? The triage group, ideally with input from the owning team. The decision should be documented, and the report should include the conditions under which it would be reopened. That way, closure is not a dead end. It is a pause with a clear path back.