Bug Report Template: Examples That Get Fixed Faster

A bug report template used by real QA teams, three filled examples (UI, API, crash), and the research on which fields actually get bugs fixed faster.

A bug report has one job: make the fix cheaper than the triage. Every sentence either moves a developer toward reproduction or sends them back to you with questions. The reports that bounce around a backlog for weeks are not badly written — they are incomplete in the same three ways every time: no exact environment, no exact data, no observable expected behavior. This guide gives you the template that survives review, three filled examples for the common report types, and the research-backed reasons each field earns its place.

What the research says about bug reports

The most-cited study on this exact question — Bettenburg, Just, Schröter, Weiss, Premraj, and Zimmermann, "What Makes a Good Bug Report?" (Foundations of Software Engineering, 2008) — surveyed 466 developers and reporters across the Apache, Eclipse, and Mozilla projects. When developers ranked which information actually helps them fix a bug, the top fields were consistent and specific:

FieldRanked value to developersWhat it prevents
Steps to reproduce #1 — the single most important field in the study "Cannot reproduce" → ticket closed, bug survives
Stack traces #2 — developers read them before the description Re-deriving the failure path from symptoms
Error messages #3 — exact text, not paraphrased Grepping the codebase for the wrong string
Test cases / input data High — a failing input is a failing test Round trips to ask "what exactly did you enter?"
Environment details High — version, OS, browser, build number "Works on my machine" arguments
Severity / priority guesses Low — developers re-triage anyway Inflated urgency that trains triage to ignore it

The study's practical conclusion matches what triage teams learn the hard way: a report with exact repro steps, the stack trace, and the verbatim error message is fixable in one pass. A report missing all three is a conversation starter, not a bug report. The template below is built directly from those findings.

The template

Copy this structure into Jira, GitHub issues, or your tracker of choice. Field order matters: summary first because triage reads only that line, environment and repro steps next because they gate everything else:

Title:    <Component>: <what happens> <when/trigger>
          e.g. "Checkout: total shows $0.00 after removing
          the last item from cart"

Severity: Blocker | Critical | Major | Minor | Trivial
Priority: P0 | P1 | P2 | P3            (set in triage, not by reporter)
Environment:
  - App/version:  v2.14.3 (staging build 2026-09-05)
  - OS/browser:   Windows 11, Chrome 140
  - Account/role: qa_user@example.com, standard user
  - Feature flag: checkout-v3 = on

Preconditions:
  - Cart contains exactly 1 item ($25.00)
  - User is logged in

Steps to reproduce:
  1. Open /cart
  2. Click "Remove" on the only item
  3. Observe the order total line

Actual result:
  - Total displays "$0.00" ...and (this is the bug) ...what exactly?

Expected result:
  - Total displays "$0.00" AND the "Proceed to checkout" button is
    disabled; today it is enabled and the next screen errors.

Evidence:
  - Screenshot: link
  - HAR/video: link
  - Request IDs: req_9f2c1a

Notes/links:
  - Started after the 2026-09-04 deploy; TC-CART-011 also fails.
  - Possibly related: JIRA-1234.

Two fields get deleted by every team eventually, so be honest about them: Priority belongs to triage, not the reporter — include it only if your process expects a recommendation. And "Severity" is about impact, not effort: a typo on the invoice page that prints the wrong currency symbol is Minor severity even though the fix touches money code.

Severity and priority, quickly

Teams argue about these two words more than any other part of the template. The distinction that survives review: severity is the impact if the bug ships, priority is the order you fix it in — and priority is a business decision, not a QA one.

LevelSeverity (impact)Example
BlockerWorkflow stops; data loss or security exposureEditor paste loses the last paragraphs (Example 3)
CriticalCore feature wrong for all users; wrong data servedAPI returns refunded orders to integrations (Example 2)
MajorFeature broken for a common path; workaround existsAvatar upload silently fails (Example 1)
MinorCosmetic or edge-path defect; no user harmWrong currency symbol on a rarely seen invoice line
TrivialNo functional impactMisaligned label on a settings toggle

Example 1: UI bug, written well

FieldValue
TitleSettings: avatar upload accepts a 20 MB file, then the page hangs for ~30s and silently fails
SeverityMajor
EnvironmentApp: staging 2026-09-06 · Browser: Chrome 140, macOS 15 · Account: qa_user@example.com
PreconditionsLogged in; no avatar set.
Steps1. Open /settings/profile. 2. In "Avatar", click "Upload" and select avatar_20mb.png (attached). 3. Wait on the settings page.
Actual resultUpload button shows a spinner ~30s, then reverts. No error message. Console shows 413 Request Entity Too Large on POST /api/avatar.
Expected resultEither the file picker rejects files >5 MB up front with "Images must be under 5 MB", or the 413 surfaces as an inline error. Silent failure is the bug.
Evidencescreen-recording.mp4; console screenshot attached.
NotesTC-PROFILE-007 (5 MB boundary) also fails — same root cause.

What makes this one land: the reporter separated the symptom (hang, silent revert) from the mechanism (413 in console) from the product expectation (reject early or show the error). The developer can start at the network layer without re-deriving any of it.

Example 2: API bug

FieldValue
TitleAPI: GET /v2/orders ignores the status filter and returns all orders
SeverityCritical (wrong data exposed to integrations)
Environmentapi.staging.example.com, token for test-tenant-7
PreconditionsTenant has 3 orders: two "paid", one "refunded".
Steps1. GET /v2/orders?status=paid with the tenant token.
Actual resultHTTP 200. Body lists all 3 orders, including the refunded one. Response header X-Total-Count: 3.
Expected resultOnly the 2 paid orders; X-Total-Count: 2. Per docs (link to API reference section), status is a strict filter; unknown statuses must 422, not be ignored. Verified that ?status=bogus also returns 200 with all orders.
Evidencerequest.har; response JSON attached.

The extra probe — ?status=bogus — turns a single bad response into a diagnosis: the parameter is ignored entirely, not mis-mapped. Probing once before filing saves the assignee a round trip. To run this kind of check yourself before writing it up, the API Tester fires the requests and shows status/headers side by side, and the JSON Formatter makes the response diffable when you attach evidence.

Example 3: crash / data-loss bug

FieldValue
TitleEditor: pasting 50k+ characters freezes the tab (Chrome)
SeverityBlocker for the docs-team workflow (no data loss observed)
Environmentapp v2.14.3 staging; Chrome 140, Windows 11
PreconditionsAny document open with edit rights.
Steps1. Paste a 52,000-char text (file attached: bigpaste.txt). 2. Attempt to type within 2 seconds.
Actual resultTab freezes 8–12s, then recovers. Last 1–2 paragraphs of the paste are missing after reload (autosave raced the freeze).
Expected resultPaste completes within ~1s; nothing lost. (If a size cap is intended, surface it as a message instead of freezing.)
Evidencebigpaste.txt; before/after screenshots; doc ID doc_771.
Notesreproducible 4/4 on staging; not reproducible on the 5k paste, so the trigger is roughly >20k chars.

Note the boundary hunting: "reproducible at 50k, not at 5k" converts a crash report into a starting point for the fix. Severity stays Blocker because data loss occurs, even though the freeze alone would only be Major.

Why this template works: the triage math

  • Title as a filter. Triage scans titles. Component-prefixed, trigger-suffixed titles let an owner self-assign without opening the ticket.
  • Environment as a gate. "Works on my machine" arguments end when the build number, browser, and flags are in the report. Flag-dependent bugs (the checkout-v3 example) are undiscoverable without this field.
  • Exact steps as the reproducibility contract. A report that another person can run verbatim is reproducible by definition. Everything else is commentary.
  • Actual vs expected as two lines. When the expected result is missing, developers guess product intent — usually by asking the reporter, a day later. State the intent inline, and cite the spec line if one exists.
  • Evidence as leverage. A HAR file or request ID turns "cannot reproduce" into a server-log lookup. For network issues, capture the exchange: our guide to debugging DNS, SSL, and headers covers reading what the HAR shows.

Common anti-patterns

  • "It doesn't work." No component, no action, no expectation. Bounces at triage.
  • Multiple bugs in one report. Three bugs, one ticket = one fixed, two forgotten. Split them; link them if related.
  • Screenshots without text. A screenshot of an error message cannot be grepped or translated. Paste the message text too.
  • Opinions in the title. "Checkout is a disaster" is not a title. State the behavior; the opinion goes in discussion.
  • Missing build/env. A fix verified against the wrong build looks like a regression next sprint.

When a reported bug turns out to be an input-validation gap, that is a test-case gap wearing a disguise — fold it back into the suite. Our guide on how to write test cases covers the follow-through: turn every escaped bug into at least one new case that would have caught it.

Tooling notes

If your team uses Bugzilla, the Mozilla project's own bug-writing guidelines predate and match this structure — severity/symptom separation included. Chromium's bug reporting guidelines add the same advice from the browser side: exact version numbers and minimal repro steps. The template above is deliberately compatible with both, so reports stay portable across trackers.

Related reading