All articles
  • Defect management
  • Jira
  • QA process

How to Write a Bug Report a Developer Can Actually Fix

The difference between a bug report that gets fixed today and one that sits in the backlog for a month is almost never the severity. It is the write-up.

Muhammad Asadullah Kissana7 min read

Most rejected bug reports are not rejected because the bug is not real. They are rejected because the developer could not reproduce it, could not tell what was expected, or could not work out whether it mattered. Every one of those is a writing problem, and writing problems are fixable.

Here is the structure I use for every ticket I file.

Start with the title the developer will scan

A title has one job: let someone reading forty tickets decide in two seconds whether this one is theirs. That means it needs the what, the where, and the condition.

Weak:

  • Booking broken
  • Error on save

Strong:

  • Checkout: total excludes shipping when a discount code is applied
  • Hangar booking: user with Viewer role can cancel another operator's booking

The second set can be triaged, assigned, and prioritised without opening the ticket. That alone speeds up a release.

Write reproduction steps someone else can follow

The test is simple: could a developer who has never used this feature follow your steps on a clean environment and see the bug? If any step requires knowledge you have and they do not, the report is incomplete.

Environment: staging, Chrome 120, Windows 11
Account: viewer-role test user (viewer@example.test)
  1. Log in as the Viewer-role user
  2. Go to Bookings > All Bookings
  3. Open any booking created by a different operator
  4. Click "Cancel booking"

Expected: the Cancel action is not available to a Viewer role Actual: the booking is cancelled and the operator is emailed ```

Three things make that work: the environment is stated, the account and its role are named, and expected and actual are both written down. Never assume the expected behaviour is obvious — half the arguments in a triage meeting are two people holding different assumptions about what should happen.

Separate severity from priority

These get conflated constantly, and conflating them is how a cosmetic issue ends up blocking a release while a data-corruption bug waits.

  • Severity is technical impact. Does it corrupt data, block a core flow, or misalign a label?
  • Priority is business urgency. Is it on the critical path for this release?

A typo in the footer is low severity and, the week before a launch event, possibly high priority. A rounding error in an invoice total is high severity regardless of what anyone wants to ship. State both and let the product owner make the call with real information.

Attach evidence, but the right evidence

A screenshot of an error message is useful. A twelve-minute screen recording is not — nobody will watch it.

What actually helps:

  • A screenshot with the problem area visible, cropped to the relevant part
  • The exact error text as text, not only as an image, so it is searchable
  • The relevant console or network error, including the request payload and status code
  • For data bugs, the query and its result showing the incorrect state

That last one is worth the extra five minutes. "The total is wrong" invites debate. A query result showing the persisted value alongside the expected calculation ends the conversation.

Make it one bug per ticket

A ticket containing four issues gets partially fixed, partially forgotten, and closed. It also cannot be prioritised, because its parts have different severities. Split them, even when they share a root cause — you can link related tickets, and the developer will spot the shared cause themselves.

Say what you already ruled out

This is the step most testers skip, and it saves the most time:

Not browser-specific — reproduced in Chrome, Firefox, and Edge. Not a caching issue — reproduces after a hard refresh and in a private window. Only occurs when the discount is percentage-based; fixed-amount discounts calculate correctly.

You have already done that work while investigating. Writing it down stops the developer redoing it, and the last line in particular often points straight at the faulty branch in the code.

Re-test properly when it comes back

A fix is not verified because the original steps now pass. Before closing:

  1. Re-run the original reproduction steps.
  2. Test the neighbouring cases — if percentage discounts were broken, re-check fixed-amount ones too.
  3. Check that the fix did not break the surrounding flow.
  4. Note in the ticket what you verified, and on which build.

That last note matters months later, when someone asks whether this was ever actually tested.

Why the write-up is the job

It is tempting to think finding the bug is the skill and the ticket is admin. In practice, a well-written report is how a QA engineer's work turns into a fixed product. A defect nobody can reproduce has the same value as a defect nobody found — and the report is the only part of your work most of your team will ever read.

Work with Asadullah Kissana

Available for QA contracts, consulting, and full-time roles — and for web and mobile builds through aimEncoders.