“Cannot reproduce” is the most common way a bug report dies, and it is worth reading the phrase carefully, because it does not say what people think it says. It is not a statement about the bug. It is a statement about two environments: theirs, where it happened, and yours, where it did not.

The bug is not in question. Somebody watched it happen. What is in question is whether you can build the conditions it needed, and most of the time the report does not contain them, because the person writing it had no idea which of the thousand things around them mattered.

What a reproduction actually needs

Steps are only one of four things, and they are the one everybody thinks about.

The same steps. What they clicked, in order, starting from somewhere you can also start.

The same state. The account, the permissions, the feature flags, the settings changed eighteen months ago, the half-finished draft sitting in the database. This is the one that breaks most attempts, because state is invisible to the person in it. They do not know their account is unusual. It is just their account.

The same data. Not a fresh test record but the specific one: the order with a refund on it, the name with an apostrophe, the list with nothing in it, the upload of forty megabytes. Seed data is tidy. Production data is fifteen years of decisions, which is the same gap that makes staging lie to you.

The same environment. Browser and build, device, network, screen size, clock, extensions. A version alone can be enough: “latest Chrome” was three different major versions in one week.

Four axes, and a report typically pins one of them. The work of reproducing is guessing the other three, which is why it takes an afternoon and why it so often ends in a shrug.

Start from the state, not the steps

The instinct is to follow the steps and see what happens. The better first move is to ask what would have to be true for those steps to fail.

If the checkout breaks at the payment stage, the steps are three clicks anybody can do. What is not universal is the basket, the address, the payment method, the currency, whether this account has ever been refunded. Work out which of those could change the outcome, and you have turned a vague report into three or four specific experiments.

Weak
Followed the steps on a test account. Works fine. Closed as cannot reproduce.
Better
Steps work on a fresh account. The reporter's account has a saved card from a currency we stopped supporting, and the failure is in the currency lookup. Reproduced by adding one to a test account.

The second version is not more effort. It is the same effort pointed at the right question.

Get the reproduction down to the smallest thing that still fails

Once it fails reliably, take pieces away. Remove a step, remove a field, use a smaller file, turn off an extension, cut the data down. Each removal either keeps the failure, in which case that piece was not needed, or stops it, in which case you have just found something that matters.

This is worth doing even when you already have the fix, for two reasons. A minimal reproduction is a test case somebody can keep. And the act of minimising very often finds the cause before you have looked at any code: the bug that only survives when the list is empty is telling you what it is.

Watch for the reproduction that works only sometimes. That is not a failed reproduction, it is a different bug shape, and the intermittency is data rather than noise: something is racing, or depends on order, or on a cache being cold. The same logic that makes a flaky test worth investigating rather than rerunning applies here.

The ones you cannot reproduce by construction

Some failures cannot be rebuilt on your machine, and no amount of persistence changes that. Recognising them early is worth more than trying harder.

It needed their clock. A device whose time is wrong produces certificate failures, expired sessions and impossible timestamps. That was three of the five causes behind a certificate warning.

It needed their network. A corporate proxy, a DNS filter, a captive portal, a mobile carrier that rewrites requests. You cannot join that network, so you cannot see what it does.

It needed their build. A staged rollout put a fraction of users on a version nobody else has, including you.

It needed the moment. A deploy halfway through, a cache that was cold, a third-party service that was slow for ninety seconds. The state that caused it stopped existing before the report was written.

It needed their extensions. Something injected into the page changed it. You have different ones, so you have a different page.

For these the question is not “how do I reproduce this” but “what was true at that moment, and can I still find out?”

Which is an argument for capturing instead

Every item on that list is invisible after the fact and cheap to record at the time. The console at the moment it broke. The failing request with its status and its timing. The browser build, the screen size, the URL. None of it requires the reporter to know what matters, which is the whole difficulty, because they never do.

That is the case for a report that carries its own evidence rather than a description of it. Reproduction is a way of recovering information that was thrown away, and it is expensive precisely because the information was thrown away.

Session Replay

Free Chrome extension. One click on the page that is misbehaving captures the screenshot, the console and the network log, and hands you a link to paste into the ticket.

Get the extension

Asking the reporter again, properly

When you do have to go back, ask for the things they can actually answer, not the things you wish they had written.

Bad: “please provide exact steps to reproduce.” They already believe they did.

Better, and each of these has a decent hit rate:

  • What time did it happen, and what time does your device say it is now? Two questions, not one. The gap between them is a diagnosis.
  • Has it happened more than once? Once is a moment. Repeatedly is a state.
  • Does it happen on a different network, for example mobile data instead of wifi?
  • What is on the screen exactly? The words, not a summary of them.
  • Who else can you reproduce it with? Another account narrows it to data; another person on the same account narrows it to the device.

The bug report guide has the full shape of a good report, and the common mistakes covers what goes missing most often.

What to write when you give up

Sometimes you genuinely cannot, and closing it is the right call. Do not close it as “cannot reproduce” and nothing else, because that sentence tells the next person nothing and they will spend the same afternoon you did.

Write what you tried. Which account, which browser and build, which data, which of the four axes you varied and which you could not. Then the next report of the same thing, from a different person with a different detail, is not a fresh start. It is the second data point, and two reports that share one unusual thing are usually the whole answer.

That is also the honest version of the status. The bug was not disproved. It was not reproduced with the information available, which is a different claim and a much more useful one to leave behind.