How to write a bug report that gets accepted: structure, steps and common mistakes
A bug report is not paperwork. It is read by a person who has to reproduce the defect on their machine, work out how bad it is and decide whether to fix it now or after the release. A report that does not give them that comes back with questions, and both sides lose time.
What a report is made of
The minimum working set is nearly the same everywhere: title, environment, steps to reproduce, expected result, actual result. Severity, attachments and logs come on top — but without those five there is no report.
There is an easy self-check: hand the report to someone who knows nothing about the task. If they reproduced the defect without asking a single question, the report is done.
The title: what broke and where
A title is read in a list of a hundred lines, and people decide from it whether to open the thing. So it needs two facts: what exactly happens and in what place. «The cart is broken» contains neither.
A good title survives being cut down to one line in a list and still makes sense. A bad one has to be opened to find out what it is about.
✕
Error in an order
✓
POST /orders creates an order with an empty cart and returns 201
Steps to reproduce: exact data, not a retelling
A step is an action that can be repeated literally. «Send an invalid value» cannot be repeated: invalid values are endless, and half of them behave correctly. What is needed is the one value it broke on.
For an API that means the method, the full address with its parameters, the request body and the headers if they matter. For an interface, what was clicked and typed, word for word. Order matters too: a defect that only reproduces after signing in will not reproduce without that step.
✕
1. Open the catalogue 2. Set a weird filter 3. Nothing gets filtered
✓
1. GET /products?min_price=-500 2. Look at the status code and the number of items in data
The expected result comes from the requirements
The most common weakness in a report is an expected result invented on the spot. «It is expected that it should not be like this» is an opinion, not a requirement, and an argument about it can run forever.
The expected result is a quotation: a line from the requirements, an acceptance criterion, a point in the documentation, the behaviour of a neighbouring method that was built correctly. If there is nothing to quote, this is not a defect yet but a question for the analyst — and it is worth raising it as exactly that.
The actual result, in contrast, is written with no interpretation: status code, body, a specific number. Not «the total was calculated wrong» but «the answer has total = 1380 for two items at 690 with a 10% promo code».
Five mistakes that get a report sent back
- Two defects in one report. One gets fixed, the whole thing gets closed, and the second ships.
- Steps from memory. One thing is written, another was sent, nothing reproduces.
- Judgement instead of fact: «everything is broken», «works terribly». It is not clear what to fix.
- No environment. Which stand, which user, with what rights.
- A duplicate. Before filing it is worth searching — the board often already has one.
A complete API bug report example
This is a working example rather than a universal form. It connects the observation to the contract and preserves the exact request instead of a summary from memory.
Title: POST /orders creates an order for an empty cart and returns 201\nEnvironment: QA, build 2026.09.21-3, user qa-buyer-17\nPrecondition: the user cart is empty\n\nSteps:\n1. Send POST /api/v1/orders with a valid Bearer token\n2. Request body: {}\n3. Send GET /api/v1/orders\n\nExpected: 422; no order is created (AC-ORD-04)\nActual: 201; order_id=8412, total=0 is created\nReproducibility: 3/3\nEvidence: request/response HAR, correlation_id=7af2…
Never paste a live token, password, personal data or a full production dump. Mask secrets, replace personal data with synthetic values and share sensitive logs through the agreed security process.
Checklist before submission and retest
Severity describes impact; priority describes the business order of fixing. Scales and owners vary by team, so the rationale matters most. After Fixed, QA repeats the original steps on the stated build and checks the closest regression risk instead of closing from a developer comment.
- The title includes the action, incorrect result and affected area.
- Build, environment, role, preconditions and exact test data are present.
- Expected points to a criterion, contract or recorded decision.
- Actual contains observable facts: status, values, time, ids and frequency.
- Attachments open, secrets are masked and one report covers one defect.
- Retest covers the original scenario, the fixed build and nearby regression.
Worked example: another manager can read a client
In a CRM, manager A owns a client and manager B opens its card by direct URL. Write a report another engineer can reproduce and a team can prioritize. “Foreign client visible” alone does not identify the broken access boundary.
- Find the access rule and source of the expectation.
- Prepare two accounts and an object with a known owner.
- Repeat through the UI and direct API request.
- Keep safe evidence and assess impact.
Separate a requirement from an assumption
Look for an acceptance criterion saying managers see only assigned clients. If none exists, ask whether assignment is an access boundary or merely a default list filter. Do not present your understanding of sales workflow as an approved contract. Cite the criterion and specification version; “the requirements say so” is too vague to triage.
Make reproduction independent of the reporter
Create synthetic A and B users with the same role and a test client assigned to A. Record build, environment, client id, assignment method and exact URL or API method. First run a positive control: A can read the card. Then B requests the same id. This distinguishes an ownership leak from a broken or intentionally public endpoint.
Prove what happens at the system boundary
A hidden link is not access control. Copy GET /clients/{id} from Network and replay it with B’s session; check PATCH only in an approved test environment. Record status, a redacted response and whether data changed. If the API denies access but the UI shows a cached card, report that as a separate defect rather than mixing two causes.
Prioritize and retest
A leak of customer contact data may be severe even if rare. Escalate through the team’s security channel, without attaching real personal data to a broadly visible issue. After the fix, repeat the original request, reversed ownership, direct URL, list and export. Patching one endpoint may leave another open. State the fixed build and exact retest scope.
Title: Manager B reads client assigned to A via GET /clients/481\nEnvironment: QA, build 1842; synthetic A and B, same role\nExpected: 403/404 per ACL-07; no client data\nActual: 200 with client name/email; reproduced 3/3\nEvidence: redacted response and correlation_id; no real PII\nScope: GET confirmed; PATCH, list and export not yet checked
What makes this report strong?
A teammate can reproduce it without clarification, see the source of the expected result and access evidence without exposing sensitive data. Confirmed facts are separated from hypotheses about neighboring endpoints. A later retest names the build where the fix was actually deployed.
Second case: an intermittent defect without stable steps
Checkout occasionally stalls after order confirmation, perhaps once in twenty runs. This is neither a reason to discard the finding nor enough evidence to claim a known payment root cause. Use an observation report with frequency, context and a plan to gather missing data.
Capture the observation first
Record exact time and time zone, build, browser, account, order id, amount and correlation id. Save a HAR or network exchange with cookies, tokens and personal data removed. State what the user saw, how long the wait lasted and whether a payment actually completed. “Hung” is too vague: a 12-second spinner differs from a 504 after money was charged.
Report frequency honestly
One failure in twenty attempts is an observation of 1/20, not proof of a 5% probability. State conditions and retain successful runs too. Do not experiment with live cards or a shared user account: cart history and rate limits change the result. Separate low- and high-concurrency runs if load seems relevant.
Separate symptom from suspected cause
Fact: the request returned 504 but order history shows a paid order. Hypothesis: a response was lost between services. Do not put “queue failure” in the title without logs confirming it. Compare successful and failing traces, dependency latency and message redelivery; share internal log links through the approved channel.
Specify behavior for an unknown outcome
After a payment timeout, the client cannot know whether the charge occurred. The contract should allow status lookup or safe retry with the same idempotency key without a second charge. Name the violated invariant: order and balance disagree, the UI invites a blind retry, or replay creates a duplicate. A generic “timeout bug” hides the real risk.
Plan retest and monitoring
After a fix, repeat the original data and factors that increased failure frequency. Check payment count, operation log and final status, not just a green UI. Zero failures in twenty reruns is not mathematical proof of a fix. Document run count, production monitoring and the threshold the team accepts.
Observed: checkout timeout at 14:03:27 UTC, HTTP 504\nOrder 8412: paid after timeout; UI still shows Pay\nFrequency: 1 failure / 20 attempts on QA build 1842\nEvidence: redacted HAR, correlation_id=7af2, ledger id\nHypothesis: response lost after charge (unconfirmed)\nRisk: retry may cause a second charge\nNext: compare traces; replay with same idempotency key
When should this be filed?
File a defect when an observable deviation and meaningful risk exist even without fully stable steps. State frequency, evidence, hypotheses and limits. If the deviation itself is not confirmed yet, open an investigation item with the same facts rather than inventing a confident root cause.
Common bug-report questions
Should I report a defect that happened only once?
Yes when the impact is meaningful and evidence exists. State the frequency, exact time, data and logs without claiming stable reproduction. A rare payment failure matters more than a reliably misaligned margin.
Who sets severity and priority?
There is no universal rule. QA often proposes severity while product or triage owns priority, but a team may work differently. Shared definitions and a written rationale matter more.
What if there is no requirement?
Record the behaviour and risk as a question or discovery item, obtain a product decision and then define expected behaviour. A personal preference is not automatically a defect.
A report is a working document, and the only way to learn to write one is to write a few dozen: on a real defect, not on an invented example.