Skip to content
Bugwise
Menu
Tutorials

How to Write a Bug Report

Learn how to write bug reports developers can act on right away — titles, steps, expected vs actual, severity vs priority, evidence for mobile and web, and the bug life cycle — with a full worked example and a hands-on exercise.

beginner Mobile & web
Short on time? Switch to the quick version.

You’re testing a shopping app. You add a pair of shoes to the cart, go to checkout, type in a card number, and the Pay button just… stays grey. You found a bugBugA problem in the software that makes it behave differently from what is expected.Open in glossary →. Congratulations!

Now comes the part that decides whether that bug ever gets fixed: writing it down. A great find with a poor report often ends up as “Cannot reproduce” and quietly disappears. A great report gets picked up, fixed and shipped, sometimes the same day.

Why bug reports matter

A bug reportBug reportA clear written description of a bug so developers can reproduce and fix it.Open in glossary → is a written description of a problem, detailed enough that someone else can see the bug for themselves. That last part is the whole point:

Your report is a set of instructions for recreating the problem, plus the evidence that it’s real. It’s read by more people than you might think:

If you’ve read How to Write Test Cases, a lot of this will feel familiar. A bug report is like a test caseTest caseA written set of steps, data and an expected result used to check one specific behavior.Open in glossary → that failed: preconditions, steps, expected result. It adds what actually happened and the proof.

The essentials

What goes into a bug report

FieldExample
IDSHOP-1423 (usually created by the tool)
TitleCheckout: Pay button stays disabled after entering a valid card on iOS 18
EnvironmentShopFast 4.12.0 (build 812), iPhone 15, iOS 18.0.1, Staging
PreconditionsSigned in; 1 item in cart; no saved cards
Steps to reproduce1. Tap Checkout 2. Select Card 3. Enter 4242 4242 4242 4242, 12/30, 123
Expected resultPay button becomes enabled and places the order
Actual resultPay button stays grey and can’t be tapped; no error shown
Severity / PriorityMajor / High
Reproducibility5/5 attempts
AttachmentsScreen recording, screenshot, device log

Write a title that says where, what and when

A good title follows a simple formula: Where + What + When.

Checkout: Pay button stays disabled after entering a valid card on iOS 18

Specific

Checkout: Pay button stays disabled after entering a valid card on iOS 18

Vague

Payment broken!!!

Severity vs priority

Want the full picture? See Severity vs Priority.

They’re independent. A typo in the app’s name on the home screen is low severity but high priority. A crash in a settings screen almost nobody uses can be high severity but lower priority.

Five habits of great bug reports

  1. One bug per report. Found two problems? File two reports.
  2. Exact steps and data. Numbered steps, real values, starting from a known state.
  3. Expected vs actual. Say what should happen and what you saw instead. Never just “doesn’t work”.
  4. Count how often it happens. Try again and write “3/5 attempts” or “5/5”.
  5. Attach evidence. A short screen recording beats a paragraph. Add logs when you can.

A great bug report

tracker.shopfast.dev/browse/SHOP-1423
SHOP-1423New

Checkout: Pay button stays disabled after entering a valid card on iOS 18

Severity
Major
Priority
High
Reproducible
5/5 attempts (always)
Component
Checkout
Labels
iospaymentsregression
Reporter
Mia Rossi (QA)
Assignee
Unassigned

Environment

App version:
ShopFast 4.12.0 (build 812)
Device:
iPhone 15
OS:
iOS 18.0.1
Environment:
Staging
Network:
Wi-Fi
Account:
mia.qa+1@shopfast.test

Preconditions

  • Signed in with a test account that has no saved cards
  • Cart contains 1 item ("Trail Running Shoes", $54.97)

Steps to reproduce

  1. Open the Cart tab and tap "Checkout"
  2. On the Payment screen, select "Credit or debit card"
  3. Enter card number 4242 4242 4242 4242, expiry 12/30, CVC 123
  4. Tap outside the fields to close the keyboard

Expected result

The "Pay $54.97" button becomes enabled (blue) and tapping it places the order.

Actual result

The "Pay $54.97" button stays grey and cannot be tapped. No error is shown under any field. The user cannot pay by card.

Notes

  • Does NOT happen on Android 15 (Pixel 8, same build 812).
  • Does NOT happen in build 4.11.2 on the same iPhone, so this looks like a regression.
  • Workaround: Apple Pay still works.

Attachments

  • pay-button-disabled.mp4
  • payment-screen.png
  • iphone15-console.log

Switch to Detailed at the top of the page for the full walkthrough: every field explained, the four severity and priority combinations, how to capture evidence on iOS, Android and the web, how to isolate a bug, the bug life cycle, and Jira tips.

Anatomy of a bug report

Teams use different tools (JiraJiraA popular tool for tracking bugs, user stories and tasks.Open in glossary →, Azure DevOps, Linear, GitHub Issues, even a spreadsheet), but good bug reports contain the same building blocks.

FieldWhat it meansExample
IDA unique reference. Usually generated by the toolSHOP-1423
TitleOne line that says where, what and whenCheckout: Pay button stays disabled after entering a valid card on iOS 18
EnvironmentEnvironmentA setup of servers, data and configuration where the software runs, such as dev, staging or production.Open in glossary →Where you saw it: app version and buildBuildA specific compiled version of the app or website that is ready to be installed or tested.Open in glossary →, device, OS version, browser and version, test environment (stagingStagingA pre-release environment that mirrors production as closely as possible.Open in glossary → or productionProductionThe live environment that real users use.Open in glossary →), networkShopFast 4.12.0 (build 812), iPhone 15, iOS 18.0.1, Staging, Wi-Fi
PreconditionsPreconditionSomething that must already be true before you can start a test.Open in glossary →The state needed before step 1: account type, data, settingsSigned in; 1 item in cart; no saved cards
Steps to reproduceNumbered, specific actions with exact test dataTest dataThe input values, accounts and records you use while testing.Open in glossary →1. Tap Checkout 2. Select Credit or debit card 3. Enter…
Expected resultExpected resultWhat should happen when you perform a test step, according to the requirements.Open in glossary →What should happen, according to the requirement or common sensePay button becomes enabled; tapping it places the order
Actual resultActual resultWhat really happened when you performed the test.Open in glossary →What really happened, described preciselyPay button stays grey and can’t be tapped; no error shown
SeveritySeverityHow much damage a bug does to the product or the user.Open in glossary →How badly the bug affects the productCritical / Major / Minor / Trivial
PriorityPriorityHow soon a bug should be fixed, based on business needs.Open in glossary →How soon it should be fixedHighest / High / Medium / Low
ReproducibilityHow often the bug happens when you follow the steps5/5 attempts (always), 2/10 (intermittent)
AttachmentsProof and clues: screenshots, screen recordings, device logs, browser console errors, network recordings (HAR files)pay-button-disabled.mp4, iphone15-console.log
Component / labelsWhich part of the product, plus searchable tagsComponent: Checkout · Labels: ios, payments, regression

Writing a great title

The title is the most-read part of your report. It shows up in lists, search results, sprint boards and notification emails. Many people will only ever read the title, so it has to work on its own.

Use the formula Where + What + When:

PartQuestion it answersExample
WhereWhich screen or feature?Checkout:
WhatWhat goes wrong, as you observed it?Pay button stays disabled
WhenUnder which condition, trigger or platform?after entering a valid card on iOS 18

Where + what + when

  • Checkout: Pay button stays disabled after entering a valid card on iOS 18
  • Order tracking: Courier map freezes after switching from Wi-Fi to mobile data
  • Search: Results show yesterday’s prices when the cache is not cleared

Vague or emotional

  • Payment broken!!!
  • Map issue
  • Bug in search
  • URGENT: app is unusable

A few rules of thumb:

  • Describe the symptom, not your guess at the cause. “Pay button stays disabled” is a fact. “Card validation regex is wrong” is a guess, and it might be wrong.
  • Skip “Bug:” and “Issue with”. Everyone knows it’s a bug; it’s in the bug tracker.
  • Keep it under about 100 characters. Details go in the description.
  • No capitals, no exclamation marks. Urgency belongs in the priority field.

Try it yourself:

Title builder

Fill in the three parts. Try an example, then write your own.

Screen or feature

What you see go wrong

Trigger, condition, platform

Your title

Checkout: Pay button stays disabled after entering a valid card on iOS 18

  • Says where (screen or feature)
  • Says what goes wrong, specifically
  • Says when it happens
  • Calm, factual tone
  • 73 characters, fits in a ticket list

Steps, expected and actual

These three fields are where most reports fall apart.

Steps to reproduce

Write steps as if the reader has never opened the app. Start from a known state (that’s what preconditions are for), use one action per step, name the exact buttons, and give the exact data.

Reproducible

Preconditions: Signed in with a test account that has no saved cards. Cart contains 1 item ($54.97).

  1. Open the Cart tab and tap Checkout.
  2. Select Credit or debit card.
  3. Enter card number 4242 4242 4242 4242, expiry 12/30, CVC 123.
  4. Tap outside the fields to close the keyboard.

A guessing game

  1. Go to checkout.
  2. Try to pay with a card.
  3. It doesn’t work.

Expected vs actual

Expected is what should happen. Point to the requirement if there is one. Actual is what did happen, described as precisely as a camera would.

Precise

Expected: The “Pay $54.97” button becomes enabled (blue). Tapping it places the order and opens the confirmation screen.

Actual: The “Pay $54.97” button stays grey and nothing happens when tapped. No error is shown under any field.

Useless

Expected: It works.

Actual: It doesn’t work.

“Doesn’t work” could mean the app crashedCrashWhen an app suddenly closes or stops working because of an unhandled error.Open in glossary →, froze, showed an error messageError messageText that tells the user something went wrong and, ideally, how to fix it.Open in glossary →, or did nothing. Each of those points to a completely different cause.

One bug per report

It’s tempting to save time by listing everything you found in one ticket. Don’t.

If two bugs seem connected (for example, the same error appears in two places), file them separately and link them. Let the developer decide whether it’s one cause.

Severity vs priority

These two fields sound similar, and confusing them is one of the most common beginner mistakes (and a very common interview question). Here’s what you need for writing reports; the in-depth lesson, with a triage practice board, is Severity vs Priority.

Typical severity levels (scales vary by team):

SeverityMeaningExample
CriticalCrash, data loss, security hole, or a core flow fully blocked with no workaround. Some teams put a separate blockerBlockerA bug so serious that it stops testing or a release from continuing.Open in glossary → level above itApp crashes on launch; payments fail for everyone
MajorA main feature is broken or wrong, but a workaround existsCard payment fails on iOS, Apple Pay still works
MinorA small feature misbehaves; the user can carry onSorting by price ignores items on sale
TrivialCosmetic: typos, alignment, colorsButton label is 2 px off-center

The four combinations

Because they measure different things, every combination is possible:

High priorityLow priority
High severityThe app crashes when the user taps Pay. Fix now.The app crashes when importing contacts from a 15-year-old phone format almost no one uses. Serious, but rare.
Low severityThe company name is misspelled on the login screen, or the price shows the wrong currency symbol before a big launch. Harmless technically, embarrassing publicly.A tooltip in a rarely visited settings screen has a typo.

Reproducibility

Before you file, follow your own steps again. Then write down how often the bug happened:

  • 5/5 attempts (always): great, the developer will see it straight away.
  • 3/5 attempts: intermittent. Still very useful; say so honestly.
  • 1/10 attempts: rare. Report it anyway, with every detail you have and a recording of the time it happened.

A bug you can reproduce every time is reproducibleReproducibleA bug that happens again every time you follow the same steps.Open in glossary →. Bugs that come and go often point to timing problems such as a race conditionRace conditionA bug that depends on the timing or order of events, so it only happens sometimes.Open in glossary →, slow networks, or leftover data in the cacheCacheStored copies of data or files that make apps and websites load faster.Open in glossary →, so the number itself is a clue for the developer.

Gathering evidence

Evidence turns “I saw something weird” into a fact nobody can argue with. Aim for at least one visual (screenshot or recording) and, when you can, logs.

Screenshot: press the Side button + Volume Up together (Home button + Side button on older iPhones). Use the markup tool to circle the problem.

Screen recording: open Control Center and tap the Screen Recording button. If it’s missing, add it in Control Center settings. Recordings are usually the single most useful attachment: they show the exact taps and timing.

Device logs: connect the iPhone to a Mac. With a debug build running from Xcode, errors appear in the Xcode console. Without Xcode, open the Console app on the Mac, select the iPhone, and filter by the app name. Developers often add their own in-app debug menu too; ask your team.

Crash logs: on the iPhone, go to Settings → Privacy & Security → Analytics & Improvements → Analytics Data and look for files starting with the app’s name.

On the simulatorSimulatorSoftware that imitates a device's behavior on your computer, like Apple's iOS Simulator.Open in glossary →: Cmd + S saves a screenshot. To record video, run xcrun simctl io booted recordVideo bug.mp4 in Terminal (press Ctrl + C to stop).

Screenshot: press Power + Volume Down together.

Screen recording: swipe down twice to open Quick Settings and tap Screen record (Android 11 and newer; the exact name varies by manufacturer). Turn on “Show touches” if offered, so taps are visible.

Device logs with adb logcat: enable Developer options and USB debugging, connect the phone, and use the Android Debug Bridge (adb) on your computer (new to it? see adb Basics):

adb logcat -c                 # clear old logs
# ...now reproduce the bug on the phone...
adb logcat -d > bug-log.txt   # save everything logged so far to a file
adb logcat '*:E'              # or: watch only errors, live (quotes stop zsh from expanding *)

Crashes usually show up as a FATAL EXCEPTION with a stack trace. Attach the file; the developer will know what to look for.

Full bug report: adb bugreport creates a zip with logs and system info. It’s large, so only attach it when a developer asks.

Open the browser’s DevToolsDevToolsDeveloper tools built into browsers for inspecting pages, network traffic and errors.Open in glossary → with F12 or Ctrl + Shift + I (Windows) or Cmd + Option + I (Mac). DevTools for Testers covers each panel in depth.

Console tab: look for red error messages. Copy them into the report as text (not just a screenshot), so they’re searchable.

Network tab: reproduce the bug with the Network tab open and look for failed requests (status codes in red, like 400, 500, or “failed”). Click one to see the request and response. Tick Preserve log so requests survive page reloads.

HAR file: a HAR file is a recording of every network request on the page. In Chrome, click the download (Export HAR) button in the Network tab. Developers can open it and see exactly what the browser sent and received.

Also note: browser name and version, operating system, window size or device emulation, and whether you were signed in. Try an incognito/private window to rule out extensions and leftover cookiesCookieA small piece of data a website stores in your browser, for example to keep you logged in.Open in glossary →.

Testing a website on an iPhone? Turn on Settings → Apps → Safari → Advanced → Web Inspector on the phone (on iOS 17 and older: Settings → Safari → Advanced), connect it to a Mac, and use Safari’s Develop menu to open Web Inspector for the page on the phone.

Isolating the bug

Finding a bug is step one. Narrowing it down is what makes you a tester developers love. Spend a few minutes asking “does it still happen if…?” Each answer goes into the Notes section of your report.

  1. Other platform? Does it happen on Android too, or only on iOS? On the website as well as the app? A bug on one platform points to platform code; a bug everywhere points to the server or shared logic.
  2. Other device or OS version? Only on iOS 18, or also iOS 17? Only on a small screen? Only on a Samsung phone? (Android fragmentationFragmentationThe huge variety of device models, screen sizes and OS versions an app must support.Open in glossary → makes this one important.)
  3. Other browser? Only in Safari, or also in Chrome and Firefox? This is the heart of cross-browser testingCross-browser testingChecking a website works and looks right in different browsers and browser versions.Open in glossary →.
  4. Other account or state? Signed in vs signed out? New account vs old account? Empty cart vs full cart?
  5. Other data? Only with this card, or any card? Only with long names, special characters, or another currency?
  6. Previous version? Did it work in the last release? If yes, it’s a regression, which is extremely useful to know.
  7. Clean state? Does it still happen after clearing the app’s cache, reinstalling, or in a private browser window?

Don’t overdo it, though. If the bug is clearly serious, report it quickly with what you have, and add findings as comments.

How to write a bug report, step by step

  1. Reproduce it. Make the bug happen again from a fresh start. Note the exact steps and data as you go.
  2. Search for duplicates. Someone may have reported it already. If so, add your details as a comment instead of filing a new one.
  3. Isolate it. Run through the “does it still happen if…” questions above.
  4. Capture evidence. Record the screen while reproducing; save logs, console errors or a HAR file.
  5. Write the title. Where + What + When.
  6. Fill in the details. Environment, preconditions, steps, expected, actual, reproducibility, severity, component, labels.
  7. Re-read it as a stranger. Could a developer who’s never seen this screen reproduce it from your text alone? Better still, follow your own steps once more, word for word.

Worked example

Here’s the bug from the start of this lesson, written up properly. Notice how it answers every question before a developer has to ask.

tracker.shopfast.dev/browse/SHOP-1423
SHOP-1423New

Checkout: Pay button stays disabled after entering a valid card on iOS 18

Severity
Major
Priority
High
Reproducible
5/5 attempts (always)
Component
Checkout
Labels
iospaymentsregression
Reporter
Mia Rossi (QA)
Assignee
Unassigned

Environment

App version:
ShopFast 4.12.0 (build 812)
Device:
iPhone 15
OS:
iOS 18.0.1
Environment:
Staging
Network:
Wi-Fi
Account:
mia.qa+1@shopfast.test

Preconditions

  • Signed in with a test account that has no saved cards
  • Cart contains 1 item ("Trail Running Shoes", $54.97)

Steps to reproduce

  1. Open the Cart tab and tap "Checkout"
  2. On the Payment screen, select "Credit or debit card"
  3. Enter card number 4242 4242 4242 4242, expiry 12/30, CVC 123
  4. Tap outside the fields to close the keyboard

Expected result

The "Pay $54.97" button becomes enabled (blue) and tapping it places the order.

Actual result

The "Pay $54.97" button stays grey and cannot be tapped. No error is shown under any field. The user cannot pay by card.

Notes

  • Does NOT happen on Android 15 (Pixel 8, same build 812).
  • Does NOT happen in build 4.11.2 on the same iPhone, so this looks like a regression.
  • Workaround: Apple Pay still works.

Attachments

  • pay-button-disabled.mp4
  • payment-screen.png
  • iphone15-console.log

The bug life cycle

Once you file a report, it moves through a series of statuses called the bug life cycleBug life cycleThe statuses a bug goes through, from New to Closed.Open in glossary →. Exact names vary by team and tool, but the idea is the same everywhere. For every status, who moves the bug and a hands-on ticket simulator, see the Bug Life Cycle lesson.

Bug life cycle

Click a status to see what it means and who moves the bug on.

Happy path

Retest fails?then back to Assigned.

Other ways a bug can end

NewOwner: Tester

You just filed the report. Nobody has looked at it yet. A lead or triage meeting will review it, check it is not a duplicate, and set priority.

Your job doesn’t end when you click Create. Watch your tickets, answer developers’ questions quickly, and when a bug reaches Retest (many teams call it Ready for test), verify it on a build that contains the fix. While you’re there, check the features around it too; fixes sometimes break neighbors, which is why teams also run regression testingRegression testingRe-running tests to check that new changes didn't break things that used to work.Open in glossary →.

Tone: factual, no blame

Bug reports are read by people who worked hard on the feature. A report that sounds like an accusation makes everyone defensive and slows the fix down. You’ll also be working with these developers every day.

Factual

The Pay button stays disabled after entering a valid card on iOS 18. It worked in build 4.11.2. Recording attached.

Blaming

Payments are broken AGAIN. Did anyone even test this before release?? This is really basic stuff.

  • Describe the product, not people. “The button stays disabled”, not “you broke the button”.
  • Stick to observations. Leave out sarcasm, guesses about who’s at fault, and words like “obviously” or “again”.
  • Be humble about causes. “This might be related to…” is fine; “the developer forgot to…” is not.
  • Say thanks when a bug is fixed. It costs nothing and builds trust.

Jira tips

JiraJiraA popular tool for tracking bugs, user stories and tasks.Open in glossary → is the most common bug tracker you’ll meet. A few habits make your reports much easier to work with:

  • Choose the issue type “Bug”, not Task or Story, so it shows up in bug filters and reports.

  • Search before you create. Use the search bar, or JQL (Jira’s query language), for example:

    project = SHOP AND type = Bug AND text ~ "pay button" AND statusCategory != Done
  • Use the fields your team uses: Affects version (where you found it), Component, Labels, Environment, Priority. Consistent fields make dashboards and filters work.

  • Link related tickets with “relates to”, “is blocked by” or “duplicates”, and link the bug to the story it belongs to.

  • Format for readability. Use numbered lists for steps and code blocks for error messages and log snippets.

  • Drag and drop attachments straight into the ticket, and give them meaningful names (pay-button-disabled.mp4, not IMG_4821.MOV).

  • @mention people only when you need their attention, and watch your own tickets so you see questions.

  • Use a template. Many teams keep a bug description template with the headings Environment, Preconditions, Steps, Expected, Actual, Notes. If yours doesn’t, suggest one.

Practice: fix this bug report

A teammate filed the report below. It has the right idea, but almost every part needs work. Find the problems, then compare it with the improved version.

Fix this bug report

A new teammate filed this ticket. Click every part you think is a problem. Some parts are fine, so think before you click.

tracker.shopfast.dev/browse/SHOP-1422
SHOP-1422
Title
Reporter
Component
Environment
Steps
Expected
Actual
Severity
Reproducible
Attachments

0 of 9 problems found

Before you submit a bug report

Before you submit a bug report

0 of 13 checked

Check your understanding

Quick quiz

0/6 answered · 0 correct

  1. 1.Why is the 'steps to reproduce' section so important?

  2. 2.Which title follows the Where + What + When formula best?

  3. 3.The company logo is misspelled on the home screen the day before launch. What is the most likely classification?

  4. 4.While testing checkout you also notice a blurry profile photo. What should you do?

  5. 5.A bug happened 3 times out of 5 attempts. How should you report it?

  6. 6.Your bug is marked 'Fixed'. What happens next?

Key takeaways

  • A bug report exists so someone else can reproduce the bug. If they can’t, it won’t get fixed.
  • Use the title formula Where + What + When, and describe symptoms, not guesses.
  • Always include environment (app version and build, device, OS, browser), preconditions, exact steps, expected and actual results.
  • One bug per report, with a reproducibility rate like “3/5 attempts”.
  • Severity is impact; priority is fixing order. They are independent.
  • Attach evidence: screen recordings, screenshots, device logs, console errors, HAR files. Remove sensitive data.
  • Isolate before you file, keep the tone factual and blame-free, and follow your bug through its life cycle to retest.

Finished this page?Nice work, this page is complete!

Mark it as done to track your progress. It's saved in this browser, no account needed.

Its review cards are now in Bites ⚡
Esc

Type to search the whole site.