Skip to main content

How to write a bug report a developer can fix without messaging you

Seven habits that turn "it's broken" into a report someone can act on, with a before/after example.

Updated 5 min readMarkdown

Every developer has received this message:

Discount codes don't work, please fix asap.

To act on it, someone has to ask which code, which page, which browser, what "don't work" means, and whether it's all codes or one. That's a day of back-and-forth for a bug that might take ten minutes to fix.

A good bug report lets someone else reproduce the problem without asking you anything. In practice that means: a specific title, numbered steps from a known starting point, the expected result, the actual result, the browser or device, and evidence such as a marked-up screenshot or console error. One bug per report.

Here are the seven habits that get you there.

1. Reproduce it once more before you write

Run the same steps again. If it happens every time, say so. If it happens one time in five, say that. Intermittent bugs need a different investigation, and knowing which kind you have saves hours.

2. Write a title that names the place, the action and the failure

Use the pattern [where] [what goes wrong] when [trigger]:

  • ✅ Checkout: Pay button does nothing when a discount code is applied
  • ❌ Payment issue

The first can be triaged from the title alone.

3. List the steps from a known starting point

Start somewhere anyone can reach: a URL, a logged-out state, an empty basket. Number each step and keep it to one action. Include the data you used: the product, the discount code, the account type.

4. Separate expected from actual

Write what you thought would happen and what did happen as two separate lines. Sometimes the "bug" is a misunderstanding of how a feature works, and this makes that obvious fast.

5. Record the environment

Browser and version, OS, device, screen size, and whether you were signed in. Layout bugs often show up at one width only, and some failures are specific to one browser.

6. Attach evidence

A screenshot with the problem circled, a short recording of the steps, and any red errors from the browser console. If a request failed, its URL and status code are often the fastest route to the cause.

7. Keep it to one bug

Found three problems? File three reports. Bundled reports get half-fixed and then closed, and the rest are lost.

Before and after: the same bug, reported twice

Before:

Discount codes don't work, please fix asap.

After:

Title:       Checkout: Pay button does nothing after applying code WINTER10
Steps:       1. Open /shop and add "Wool scarf" to the basket.
             2. Go to /checkout.
             3. Enter WINTER10 and click Apply.
             4. Click Pay.
Expected:    The payment form opens with the 10% discount shown.
Actual:      The discount appears in the total, but clicking Pay does nothing.
             No message is shown.
Environment: Chrome 130 on Windows 11, 1366 x 768, signed in as a returning customer.
Evidence:    Screenshot with the Pay button circled.
             Console: "TypeError: Cannot read properties of undefined (reading 'amount')"
             POST /api/checkout returned 422.
Frequency:   Every time with WINTER10. Works without a code.

The "after" version takes about two minutes longer to write and usually saves a day of back-and-forth. Notice how the console error and the 422 together already point a developer at the checkout handler.

Severity is not priority

  • Severity is how bad the effect is. Data loss and blocked payments are severe; a misaligned icon isn't.
  • Priority is how soon it should be fixed, which also depends on how many people hit it and what's coming up.

A homepage typo the day before launch can be low severity and high priority. If your tracker only has one field, use it for priority and describe the impact in the description.

Mistakes that slow fixes down

  • Describing your theory of the cause instead of what you saw. Report the symptom; let the investigation find the cause.
  • Cropping the screenshot so tightly that nobody can tell which page it is.
  • "Same as before" or "see last week's email" instead of repeating the steps.
  • A phone photo of the screen, which hides the URL and blurs text.
  • Leaving out that you were on a test account, a VPN, or using an extension that changes pages.
  • Reopening an old, closed report for a new problem that only looks similar.

Quick answers

How long should it be? As short as possible while still reproducible. For most bugs: a title, three to six steps, an expected line, an actual line and a screenshot. Long narrative paragraphs usually mean the report covers more than one problem.

Can't reproduce it? Report it anyway and say so plainly. Include the time it happened, what you were doing, the URL and any screenshot. Several "could not reproduce" reports about the same area often reveal a pattern.

Should I suggest a fix? Only as a clearly separate note after the facts. It never replaces steps, expected and actual.

Who sets priority? The reporter can suggest one; whoever triages the backlog decides.

Let the tooling do the tedious part

Most of the environment section and all of the console and network evidence can be captured automatically. That leaves the reporter writing only what a human has to: the title, the steps and what they expected.

Full disclosure: I build Flawsnap, which does this for websites. It adds a report button that attaches the page, browser, device, recent console messages and network requests to each report. If you just want a structure to paste into GitHub, Jira or Linear, grab the bug report template. It's plain Markdown and works in any tracker.


Originally published on flawsnap.com.

The before and after example is the strongest part. Discount codes do not work, please fix asap really does turn into a day of questions, while the WINTER10 version with steps and expected versus actual lets someone start right away. I also liked the severity is not priority point. A homepage typo before launch is a clear case of low severity and high priority, and it shows why one field cannot carry both ideas.