Skip to content
beginner Phase 4 · Bug Lifecycle & Reporting

Writing Reproducible Bug Reports

Craft reports with steps, expected and actual results, environment, and supporting evidence.

40m
0 problems
Topic Progress 0%

The Report That Gets Fixed in an Hour vs the One That Comes Back

Two reports land on the same developer's queue for the same defect class. Report A: title 'Checkout broken', two sentences of description, a screenshot of an error page. It comes back three times with questions — which browser? which card? does it happen every time? — and dies in a comment thread after a week. Report B: 'Saved-card checkout shows generic error when the card expired within 24h — total not charged, no error log entry', twelve numbered steps, expected versus actual, a HAR file, a 20-second video, environment details. It is fixed the same afternoon. The difference is not writing talent — it is a structure that removes the developer's first three questions before they are asked.

The anatomy of a reproducible report, field by field:

Summary — symptom + trigger + scope, one line. The template that works: [symptom] when [trigger condition] [scope hint]. 'Saved-card checkout shows generic error when the card expired within 24h (3 of 3 tries, Visa only tested)'. The summary carries no diagnosis — 'NullPointerException in PaymentService' may be true from the stack trace, but as the title it misleads the moment the root cause turns out to be different, and it invites the developer to skip reproduction. Symptom in the user's terms; diagnosis in a separate notes section if you have one.

Steps to reproduce — numbered, deterministic, starting from a known state. 'Given a test account with a saved Visa card that expired yesterday (test card 4000…0002, expiry set to yesterday)' — the given clause is what makes steps reproducible, because most non-reproduction is stale or unknown starting state. Each step is one action with one value: 'Select the saved card ending 4242' beats 'use a saved card'. If the defect depends on prior actions (an account state built over three sessions), the setup recipe comes before step 1.

Expected result — the rule, cited. 'The checkout completes and the order confirmation appears' — and where a requirement exists, cite it: 'per REQ-214, expired cards are rejected with the card-specific message'. Expected results grounded in requirements turn disagreements (is this even a bug?) into requirement discussions, which belong in refinement.

Actual result — exactly what happened, including what did not. 'Error page with generic message Something went wrong; order not created; no entry in the payment service log for this request (see HAR, request /v1/charge returns 500 with empty body)'. The negative observations (no log entry, no email sent) are frequently more diagnostic than the visible symptom, and they are what reporters habitually omit.

Environment — the reproduction coordinates. Build number (not 'latest'), browser + version, OS, device, test environment URL, account ID, and the feature-flag state if your product has flags. 'Latest build on staging' is unbuildable information: builds move, and the developer who reproduces against a newer build may see a different world.

Evidence — attach what proves each claim. Screenshot for the visible state, full-network HAR or the specific failing request/response for API-visible defects, console output for JS errors, video for multi-step flows where screenshots cannot show the sequence, and a screen recording that starts before the trigger — a video that begins after the failure shows the corpse, not the crime scene.

A compact complete report runs one screen. Length is not the enemy — unstructured length is; the fields above are what make a report scannable in thirty seconds by triage and deep-readable in three minutes by the fixer.

Matching Evidence to Defect Class: The DevTools-Era Bug Report

A screenshot-only reporting habit is a pre-2015 habit. Most defects a web or API tester finds leave evidence in layers the developer cannot see from your description: the network conversation, the console, the application state. Choosing evidence by defect class is the difference between a report that needs a joint debugging session and one that answers itself.

Defect class Primary evidence Why
API failure (5xx, wrong payload) HAR export or the exact request/response pair (curl equivalent) The developer needs status, headers, body, and timing — none visible in a screenshot
Frontend behavior/JS error Console output (errors + warnings) plus element screenshot Stack traces and failed resource loads point at the file and line
Layout/visual Screenshot at the affected viewport with device pixel ratio noted Visual claims need coordinates: browser, zoom, viewport size
Flow/sequence (multi-step) Video starting before the trigger + final screenshots Sequence defects die in prose; video preserves order and timing
State-dependent (cart, session) State dump: account ID, stored data, cookies/session validity window Most cannot-reproduce reports are state mismatches
Performance Network waterfall with timings + measured expectation 'Feels slow' becomes LCP 4.8s vs a 2.5s budget

The HAR file deserves special mention because it is the single most under-used evidence type. Captured via the browser devtools Network tab, it contains every request: URLs, methods, status codes, payloads, and timings — everything needed to distinguish 'the server returned an error' from 'the request was never sent' from 'the response was fine and the client mis-rendered it'. Attaching one converts a three-message debugging correspondence into a single diagnosis. Pair it with the console export for frontend defects and you have handed the developer the two layers a report usually forces them to reconstruct.

Evidence hygiene rules keep attachments trustworthy. Redact secrets — authorization headers, session cookies, real personal data — before sharing HAR files outside the immediate team; a HAR is a complete transcript, including the tokens you forgot were in it. Timestamp and name files with the build and defect ID (DEF-214.har, DEF-214-checkout-error.mp4) so attachments stay attached to their claim through triage. Point, do not dump: a 40 MB screen recording and a 200-request HAR of an entire session bury the moment of failure; trim to the window containing the trigger and the failure, and highlight the failing request in the HAR notes.

One evidence type deserves its own paragraph because it changes the job description: a minimal reproduction case. When a defect involves frontend logic, cutting a failing case into a small sandbox (a CodePen, a minimal HTML page, a curl command with only the relevant parameters) often locates the bug before the developer opens the ticket. This is not expected of every report — it is a senior move for high-priority or contested defects — and it earns a specific kind of credibility: reports that carry their own diagnosis attract same-day fixes, because the remaining work for the developer is small and unambiguous.

Interview framing: the question 'how do you write a good bug report?' wants the structure (summary, steps, expected, actual, environment) and the evidence-matching habit (HAR for API, console for JS, video for sequences, state dumps for data-dependence). Candidates who mention redaction and pointing-at-the-moment read as people whose reports have actually traveled through real teams.

The Intermittent Defect: Turning 'Sometimes' Into a Report

The hardest report to write is the defect you saw once: the payment confirmation stalled 'sometimes', you were not looking at the network tab, and by the time you looked the moment had passed. An intermittent defect reported as 'happens occasionally, could not reproduce' is close to worthless — it will be rejected as not-reproducible, or worse, accepted and never found. The craft is converting intermittence into either a reproduction recipe or a bounded statistical report. Four moves, in order.

Move 1 — reproduce before reporting, with a stopwatch. Attempt the trigger repeatedly (10-20 runs) and count outcomes. A rate changes the report entirely: 'failed 3 of 15 attempts on build 4.12.0-rc3, all three with a cold session' is a report a developer can chase; 'occasionally' is a report they will schedule for a Friday they never reach. The rate also implies a search space: 3/15 suggests a race or a cache-dependent path, which tells the developer what class of bug to look for before opening the code.

Move 2 — bisect the conditions. Intermittence almost always has a hidden condition — timing, state, or data — and bisecting finds it systematically. Split along one axis per round: cold session vs warm (session cache), first attempt vs subsequent (client-side caching), fast network vs throttled (timing races), new account vs aged account (data-dependent), single-tab vs multi-tab (concurrency). Each round halves the space; three or four rounds usually isolate the trigger to one condition ('only with a cold session under 500ms added latency' — now it is a reproducible race window).

Move 3 — capture the evidence the moment it fires. Intermittent defects need always-on capture during reproduction attempts: the network log and console left open, a screen recording running, server-side request IDs noted. When the failure fires, the trace of that attempt is preserved — the recurring failure mode of intermittent-defect hunting is the failure firing while your tools are closed.

Move 4 — report the statistics when reproduction stays partial. If bisecting narrows but does not fully reproduce, report what you have with full honesty:

Reproduction rate: 3/15 attempts; 0/10 with warm session, 3/5 cold + throttled
Conditions bisected: cold session (required), latency >= 400ms (amplifies)
Evidence: HAR for attempts 4, 9, 13 (failing request /v1/charge — timeout at 30s);
          request IDs 8f31…, a02c…, de77… for server-log correlation
Observation: all three failures show client retry #2 with an idempotency-key mismatch

This report lets the developer correlate server logs by request ID, reproduces at will under the stated conditions, and even hints at the mechanism — without claiming a diagnosis it cannot prove. It also survives triage intact: a rate-and-conditions report cannot be dismissed as not-reproducible, because the reproduction statistics are the reproduction.

The interview version of this skill: given the scenario 'you saw a flaky failure once — what do you do?', walk the four moves in order (reproduce-and-count, bisect conditions along one axis per round, always-on evidence capture, statistical reporting with request-ID correlation) and close with why it matters — intermittence is not a property of the defect being unfindable; it is almost always a hidden condition you have not isolated yet, and the QA skill is the bisect.

Quiz

1. Which defect summary follows the symptom + trigger + scope template?

Question 1 options

2. A report says 'cannot reproduce — works on my machine'. What is missing?

Question 2 options

3. Which evidence best supports a defect where the frontend shows an error after an API call fails?

Question 3 options

4. You saw a payment confirmation stall once. What is the correct report?

Question 4 options

Flashcards

Question

The seven fields of a reproducible defect report, and what each removes.

Answer

Summary (symptom + trigger + scope — sets correct expectations); steps with a *given* setup clause (removes unknown starting state); expected result citing the rule/requirement (grounds the dispute); actual result including negative observations (no log entry, no email); environment (build number, browser, OS, account, flags — reproduction coordinates); evidence attachments (proof per claim); severity/priority input (triage fuel).

Question

Why keep the diagnosis out of the defect summary?

Answer

A title like 'NullPointerException in PaymentService' anchors the investigation and misleads when the root cause differs; it also invites skipping reproduction. Report the user-visible symptom in the title and put technical observations (stack trace, suspicious log lines) in a notes section — diagnosis is a hypothesis, and hypotheses belong where they are labeled as such.

Question

Match evidence to defect class in four pairs.

Answer

API failure → HAR / exact request-response pair. Frontend JS error → console output + element screenshot. Flow/sequence → video starting before the trigger. State-dependent → state dump (account ID, session validity, stored data). Add: performance → waterfall with timings vs a stated budget.

Question

What are the HAR-file hygiene rules before sharing one?

Answer

Redact secrets (authorization headers, cookies, personal data) — a HAR is a complete transcript; name and timestamp files with the defect ID and build; trim to the failure window and highlight the failing request rather than attaching the whole session. Point at the moment; do not dump the session.

Question

The four moves for an intermittent defect, in order.

Answer

(1) Reproduce with a stopwatch — establish a rate (3/15 is a report; 'occasionally' is not); (2) bisect hidden conditions one axis per round (cold/warm session, latency, data age, tabs); (3) keep evidence capture always-on during attempts (network log, console, recording, request IDs); (4) if partial, report statistics + conditions + correlation IDs — the reproduction data itself defeats 'cannot reproduce'.

Revision Notes

Key Takeaways

  • 1. A reproducible report removes the developer's first three questions in one screen: which build/environment, which steps from which state, and what exactly happened
  • 2. Summaries state symptoms, not diagnoses; expected results cite the rule; actual results include the negative observations that carry the most diagnostic weight
  • 3. Evidence should match the defect class — HAR for API failures, console for frontend, video for sequences, state dumps for data-dependence — and arrive redacted, named, and trimmed
  • 4. Intermittent defects are usually hidden-condition defects: establish a rate, bisect one axis per round, keep capture always-on, and report the statistics with correlation IDs
  • 5. Reports carrying their own diagnosis (minimal reproductions) attract same-day fixes because the developer's remaining work is small and unambiguous

Interview Tips

  • • "Write a good bug report — what goes in it?" — deliver the field list with the purpose of each (summary without diagnosis, given-state steps, cited expected, actual including negatives, pinned environment, matched evidence); the purpose language separates structure-reciters from practitioners
  • • "The developer says they cannot reproduce your bug." — respond with the attempt record you would have attached (builds, environments, conditions varied) and offer to pair-reproduce; never accept or issue a bare not-reproducible verdict
  • • "How do you handle a defect you saw once?" — the four moves: rate first (3/15 beats 'sometimes'), bisect conditions axis-by-axis, always-on evidence capture, statistical report with request-ID correlation; close with 'intermittence is a hidden condition, not an unfindable bug'
  • • "What is in a HAR file and why attach it?" — full request/response transcript: status, headers, payloads, timings; it distinguishes server-error vs never-sent vs mis-rendered in one attachment and gives server teams correlation IDs — plus you mention redacting tokens first

Cheat Sheet

Writing Reproducible Bug Reports

Report anatomy:

Field Rule
Summary Symptom + trigger + scope; no diagnosis
Steps Numbered, one action each, given setup clause first
Expected The rule, cited to requirement where one exists
Actual What happened AND what did not (no log entry, no email)
Environment Build number (not 'latest'), browser+version, OS, account, flags
Evidence One attachment type per claim, named DEF-xxx.<ext>

Evidence by class: API → HAR · JS/console → console export + screenshot · sequence → video from before the trigger · state → account/session/data dump · perf → waterfall vs budget.

HAR hygiene: redact tokens/cookies/PII · trim to the failure window · name with defect ID · correlate with request IDs for server logs.

Intermittent playbook: count runs (rate) → bisect one axis per round (session warmth, latency, data, tabs) → always-on capture → report statistics + conditions + request IDs when partial. 3/15 + 'cold session + >=400ms latency' is actionable; 'occasionally' is not.

Senior move: minimal reproduction (CodePen / curl with only relevant params) for high-priority or contested defects.

Continue Learning

Before You Start

Related Reading