“It broke” can be completely true and still leave a development team unable to see the same failure.
A useful bug report closes that gap. It identifies one observable problem, the exact context in which it happened, the smallest path that still produces it, what the reporter expected, what actually happened, and the evidence needed to repeat the check. It keeps observation separate from diagnosis and gives the eventual correction a specific scenario to pass.
The goal is not to fill every field in a tracker. The goal is to leave a bounded evidence packet another person can reproduce without guessing.
Report one observable issue
Start with one behavior. A report titled “checkout is broken” may contain a disabled button, a rejected address, a duplicate confirmation, and a missing receipt. Those could have different causes, owners, and retest paths.
Choose the earliest observable failure that blocks the task. Describe what the person was trying to accomplish and what stopped them.
Mozilla’s Bugzilla guidance on writing a bug report recommends a precise summary, reproducible steps, actual results, and expected results. That guidance is written for Mozilla’s Bugzilla workflow. The transferable practice is narrower: make the report specific enough that a second person can follow the same path and compare results.
A concise title usually names:
- the affected area;
- the action or condition;
- the observed behavior.
For example:
Invoice export — selecting a custom date range downloads an empty file
That title describes an observation. “Fix the export query” proposes a correction before the implementation has been investigated.
Record the exact context
Software behavior depends on context. “Latest version” and “normal browser” become ambiguous as soon as a release changes or a second person uses a different environment.
Capture what identifies the tested state:
- product, application, page, or workflow;
- version, build, release commit, or deployment identifier;
- device and operating-system version;
- browser or client version;
- relevant configuration and feature state;
- signed-in or signed-out state and the kind of test account used;
- viewport, locale, time zone, permissions, connectivity, or other conditions that affect the path;
- occurrence time, including time zone;
- last version or date when the same path was known to work, if that is verified.
Apple’s Feedback Assistant guidance asks reporters to identify the relevant topic, platform and version, provide detailed reproduction steps plus actual and expected results, record occurrence context, and attach relevant diagnostics or evidence. That does not define a universal bug-report schema. It does show why product and environment identity matter: the person investigating needs to know which system state the evidence describes.
Do not add context merely because a field exists. Record the details that can change the result, and label unknowns as unknown rather than filling them with assumptions.
Preserve prerequisites and starting state
Steps are not reproducible if the starting state is hidden.
Before step one, record the prerequisites:
- the test account has a specific role;
- an order contains two line items;
- a setting is enabled;
- a form starts empty;
- a notification has not already been sent;
- a file was created with a particular supported version;
- the previous attempt was cleared or intentionally retained.
Use safe, non-sensitive test data. Do not paste credentials, session tokens, API keys, private customer records, payment details, unrestricted production logs, or unrelated personal information into an ordinary ticket.
If the issue involves a real customer record, security weakness, private data, or another sensitive condition, use the product’s protected reporting and support path. A public issue tracker is not automatically an appropriate evidence store.
Reduce the path without changing the failure
Write numbered actions that begin from the recorded starting state. Include the values or choices that matter.
Then remove unnecessary steps one at a time and check whether the failure still occurs. A shorter path is easier to repeat and helps identify the boundary of the problem. Do not shorten it by silently changing the state.
Firefox source documentation for filing good bugs asks contributors to use a descriptive title, explain the problem and reproduction steps, include details such as the operating system and version, and provide a test case when applicable. That is Mozilla contribution guidance, not a promise that every team must use the same tracker or component structure. The useful discipline is to make the path and its context inspectable.
Write actions, not conclusions:
- Open the invoice list while signed in as the fictional test manager.
- Choose Export.
- Select Custom range.
- Set the fictional start and end dates recorded in the report.
- Choose Download CSV.
- Open the downloaded file in the named application.
Avoid steps such as “make the export fail” or “use the bad date.” Those require the investigator to guess what the reporter did.
Separate expected, observed, and suspected
Use three separate fields.
Expected result states what the product, requirement, prior verified behavior, or user-facing instruction led the reporter to expect.
Observed result states what actually happened in the recorded environment. Include exact visible wording when it is short and useful, but do not dump unrestricted logs into the report.
Suspected cause is optional and clearly labeled as a hypothesis. It does not replace the steps or observed evidence.
The Chromium bug reporting guidelines ask reporters to provide a high-level problem description, detailed reproduction steps, expected behavior, cross-browser observations when relevant, screenshots, and a simplified test when possible. That guidance belongs to Chromium’s reporting process. It reinforces the distinction between a report someone can exercise and a conclusion someone merely asserts.
“The export query ignores the end date” may become a useful engineering hypothesis. “The downloaded file contains headers but no data rows after these six steps” is the observation that still needs to be reproduced.
Record frequency without hiding an intermittent failure
A report does not become useless because the failure happens sometimes.
Record the attempts:
- 3 of 5 attempts in the same recorded environment;
- every attempt after a clean sign-in;
- only the first attempt after changing the setting;
- once at 10:42 AM Central, not reproduced in three later attempts;
- unknown because the action would have a consequential production effect and was not repeated.
Do not turn “not reproduced on the second try” into “did not happen.” Preserve the original evidence, occurrence time, state, and any known difference between attempts.
Also separate impact from severity. “A customer cannot complete the invoice export needed for today’s reconciliation” is an observed task impact. “Critical priority” is a triage decision that may depend on scope, alternatives, frequency, data risk, and current operating commitments.
A detailed report does not guarantee priority, a response time, a diagnosis, or a correction. It gives the team better evidence for those decisions.
Attach the smallest useful evidence
Evidence should help a second person understand the failure, not bury it.
Useful evidence can include:
- a short screenshot showing the relevant state;
- a bounded screen recording that begins before the failure;
- the exact error message;
- a small non-sensitive fixture file;
- a request or correlation identifier that an authorized operator can look up;
- a short, reviewed log excerpt;
- before-and-after state when the transition matters.
Review every attachment before sharing it. Crop unrelated windows. Remove secrets and unrelated personal data. Confirm that a fixture contains fictional or approved test information. Keep security-sensitive technical details in the protected reporting channel intended for them.
GitHub’s documentation for issue forms explains how a repository can request structured input through text areas, dropdowns, checkboxes, and validation. That is GitHub-specific configuration guidance. A form can prompt for evidence, but it cannot make a vague observation precise or make unsafe data appropriate to publish.
Copy this reproducible bug report worksheet
The completed example below is fictional. Harbor Ledger is an imaginary browser-based invoicing tool, and every version, account, date, file, observation, and result in the table is invented for this article. It is not a Fireproof Studio product, customer report, security disclosure, or production result.
On a phone or other narrow screen, swipe the table horizontally to read every column.
| Summary | Version or release | Environment | Prerequisites and starting state | Smallest repeatable steps | Expected result | Observed result | Frequency and last known working state | Evidence | Task impact | Owner | Retest |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Invoice export — custom date range downloads an empty CSV | Fictional Harbor Ledger web build 2026.11.05-test.2 | Fictional desktop browser 142; fictional OS 27.1; 1440×900; Central time; signed in as test manager | Fictional workspace with three approved test invoices dated Nov. 1–3; export history cleared; no customer data | 1. Open Invoices. 2. Choose Export. 3. Select Custom range. 4. Enter Nov. 1–3 fictional test dates. 5. Choose Download CSV. 6. Open the file. | CSV contains one header row and three fictional invoice rows for the selected dates | CSV contains the header row and no invoice rows; no visible error appears | 3 of 3 attempts after clean sign-in; same fixture exported three rows in fictional build 2026.11.04-test.7 | 18-second cropped recording; empty 312-byte fictional CSV fixture; fictional correlation ID retained in protected test record | Test operator cannot complete the invoice-reconciliation task through this path; no production customer impact was tested | Export workflow owner | Repeat the exact six steps in the corrected build, confirm three rows and no duplicate export, then test the preset “Last 7 days” path |
| Invoice export — custom date range downloads an empty CSV | Same fictional build | Same fictional environment with an alternate browser locale | Same safe fixture; existing downloaded file removed before each attempt | Same six steps after switching browser locale to the fictional alternate locale | Result still contains the same three approved fixture rows | Three rows downloaded correctly | 1 of 1 adjacent-path attempt; no earlier evidence for this locale | Bounded result note only; no additional attachment | Adjacent locale path passed in this test; it does not close the original failure | Export workflow owner | Preserve as adjacent regression evidence after the exact failure passes |
Copy the headings into the team’s approved issue tracker or test record. Add rows when the environment, starting state, path, or result changes materially. Do not combine unrelated symptoms merely to keep one ticket.
Connect related systems without losing the source of truth
A bug report can refer to a support request, monitoring event, release record, or protected diagnostic without copying every detail into every system.
Choose which record owns the current status and link the others to it. Our guide to choosing a source of truth before connecting business tools explains why duplicate editable copies create conflicting ownership and recovery problems.
For an automated workflow, also record whether the failed action can be retried safely, could duplicate work, or needs a human decision. The automation failure plan covers run identity, alert ownership, retry boundaries, and final-state verification. A bug report describes the reproducible product behavior; an operating plan describes what the team does while that behavior remains unresolved.
Retest the failure shape, not a convenient substitute
A code change, configuration edit, or successful unit test is not the same as verifying the reported scenario.
After a correction:
- identify the exact version or deployment under test;
- recreate the recorded prerequisites and starting state;
- follow the same smallest steps;
- compare the result with the recorded expectation;
- preserve the retest evidence;
- exercise one adjacent path in proportion to the change;
- record anything still unverified.
“Fixed” should mean the affected scenario passed in the intended version and environment, not merely that a developer changed related code.
If the original issue was intermittent, repeat enough attempts to make the result meaningful and report the count honestly. A successful attempt does not erase earlier failures. A failed attempt after the correction does not become an unrelated follow-up simply because most attempts passed.
Leave the next person a report they can use
A reproducible bug report is a handoff between the person who saw a failure and the person who must investigate and verify it.
Name one observable issue. Record the exact context and starting state. Reduce the steps without changing the failure. Separate expectation, observation, impact, and suspected cause. Share only the smallest safe evidence. Record frequency honestly. Then retest the exact failure shape and one adjacent path in the intended version.
That does not guarantee a fix. It replaces guessing with a bounded scenario the team can investigate, correct, and verify.
Need help planning or improving an application? Tell Fireproof Studio what the software needs to accomplish.
