Blog / 2026

How to reproduce a bug a user reported but you cannot trigger

· 6 min read

“It says the payment failed.”

You open the page. Payment works. You try a different card, a different browser, an incognito window. Payment works. The user is not lying and you are not incompetent, but somewhere between their machine and yours there is a difference you cannot see, and until you find it you cannot fix anything.

This is the most expensive category of bug, not because it is hard to fix, but because it is hard to see. Here is a process for it.

Why “works on my machine” happens

Almost every irreproducible bug comes from one of six differences:

  1. State. Their account has data yours does not. An expired subscription, a half-completed onboarding, a coupon already redeemed, 400 items in a cart.
  2. Timing. A race that only loses on a slow connection, or only wins on a fast one. Your local API responds in 8 ms; theirs took 3 seconds.
  3. Environment. An older browser, a locale that formats dates differently, a timezone where “today” is yesterday, a currency with no decimal places.
  4. Interference. An ad blocker, a password manager rewriting a form, a corporate proxy, a browser extension injecting scripts.
  5. Path. They arrived somewhere by a route you never take — a deep link, a back button after a redirect, a form resubmitted after a refresh.
  6. Scale. Something that works with 3 rows and times out with 3,000.

Notice that four of these six are invisible in your logs. A 500 shows up in error monitoring. A user who clicked a button that silently did nothing shows up nowhere at all.

The process

1. Get the boring facts first

Before theorising, establish: what URL, what time, what browser, signed in as whom. Half of all irreproducible bugs collapse the moment you learn the person was on a page you did not realise existed, or was not signed in when you assumed they were.

If you have to ask the user for this, ask for the time and the page. Those two narrow the search more than anything else, and they are the two people can actually answer.

2. Check your error monitoring, and expect nothing

Search the window around their report. If there is a stack trace, you are finished — go fix it.

Most of the time there is nothing, and that absence is informative. It means the failure was handled, or happened client-side in a way nothing reported, or was not a failure at all but a UI that did not respond. A caught exception with an empty catch block produces exactly zero telemetry and infinite user frustration.

3. Reconstruct the state, not the steps

The instinct is to replay the steps the user described. This usually fails, because the description is a reconstruction — people remember what they intended, not what they did.

Better: recreate their state. Impersonate the account if you have that facility, or clone its data into a local fixture. A surprising share of these bugs reproduce instantly once the data matches and never reproduce from the steps alone.

4. Throttle everything

If state does not do it, suspect timing. Open devtools, set the network to slow 3G and the CPU to 6× slowdown, and try again. Race conditions that never lose locally lose reliably at 400 ms of latency.

This one step finds more “irreproducible” bugs than any other, because developers work on fast machines with local APIs and users do not.

5. Stop guessing and read the session

Everything above is inference. If you record sessions, you can skip to observation.

A session recording answers the questions that the bug report cannot: what they clicked, in what order, what the page did in response, whether a request failed, and whether anything was ever shown to them about it.

The workflow is what makes this useful or useless. If your tool gives you a video, you have traded a reproduction problem for a “watch 40 minutes of footage” problem. What you want is a filter — sessions on this URL, in this window, containing an error — and then a readable account of what happened.

UserTapes derives a text transcript from every recording:

- 0:19 click button "Apply coupon"
- ⚠ 0:20 POST https://example.com/api/coupon · 422
- ⚠ 0:23 rage click ×4 · button "Apply coupon"
- ⚠ 0:41 typed into a form but left without submitting (heuristic)

Four lines, and the bug is fully specified: the coupon endpoint returned 422, nothing surfaced it, the user hammered the button and left. You now know the fix — surface the error, disable the button while the request is in flight — without ever reproducing it.

6. Write the failing test before the fix

Once you know the cause, encode it. The conditions that made this bug invisible — unusual state, slow network, a specific path — are exactly the conditions your test suite does not currently cover.

Letting the agent do the reading

If you use a coding agent, this is one of the places it pays for itself, because the bottleneck is reading, not thinking.

With session data exposed over MCP, an agent can query sessions the same way it queries your codebase — find the ones with errors, read the transcripts, and correlate them against the code it already has open:

$ claude "a user reported checkout failing around 2pm — find it"

▸ usertapes list_tapes(has_errors: true, created_after: "2026-07-29T13:00:00Z")
  ← 3 tapes · 2 with rage clicks on "Apply coupon"
▸ usertapes read_transcript(3e7128f8)
▸ diagnosis: checkout.js swallows 422s — no error shown, button stays live

The setup is covered in session replay over MCP.

When you genuinely cannot reproduce it

Sometimes the answer is that you have insufficient evidence, and the correct move is to improve observability rather than keep guessing:

  • Add an error state. If the bug is “nothing happened”, the fix might be entirely about making failure visible. That also makes the next report specific.
  • Log the handled failures. Every empty catch block is a place a user can have a bad time silently.
  • Start recording. If you had no session data this time, you will have the same problem next time.

The measure of a good process here is not how fast you fixed this bug. It is whether the next report of its kind arrives with enough information attached that there is nothing to reproduce.


Related: what is a rage click, which is usually the first visible symptom of exactly this class of bug, and session replay for developers.

Free tier · no card · no expiry

Give your agents eyes.

Record 100 sessions free, forever. Cookieless, inputs masked at the source, and full MCP access on every plan — including this one.

● Start recording