Effective Bug Reports
A bug report is a persuasive document. Its job is to make the developer reproduce the issue in under two minutes and understand its impact immediately. A great bug report gets fixed in hours. A vague bug report sits in the backlog for weeks, gets deprioritized, and eventually the reporter is asked "can you still reproduce this?" — because nobody else could.
The Five Essential Fields
Every bug report, regardless of your tracking tool (Jira, Linear, GitHub Issues, Bugzilla), must include these five fields:
1. Environment
OS, browser/version, device, API version, build number, feature flags enabled. This is the "where" of the bug.
Environment: Chrome 122, macOS 14.3, staging environment, build #4521
Feature flags: new_checkout_flow=true, dark_mode=false
Without environment details, the developer's first question is "what browser?" — and the bug report is already delayed.
2. Steps to Reproduce
Numbered, minimal. Strip away anything that is not required to trigger the bug. If you can reproduce with 3 steps, do not include 10.
Steps to Reproduce:
1. Navigate to https://staging.example.com/login
2. Enter email: user+tag@test.com
3. Enter password: ValidPass123!
4. Click "Sign In"
Minimal means minimal. Do not include "Open browser" as a step. Do not include navigation through the homepage if a direct URL works. The goal is the shortest path to the bug.
3. Expected Result
What the spec, design, or common sense says should happen. Be specific about the observable behavior.
Expected: User is authenticated and redirected to /dashboard.
The welcome message "Hello, user+tag@test.com" is displayed.
4. Actual Result
What actually happened. Include evidence: screenshots, console errors, network traces, response bodies.
Actual: Server returns HTTP 500. Response body: {"error": "invalid_parameter"}.
No client-side errors in the console. Network tab shows the POST /auth/login
request failed with 500.
5. Severity and Priority
See the Severity vs Priority file for details. Always include both.
Bad vs Good Bug Reports
| Aspect | Bad | Good |
|---|---|---|
| Title | "Login broken" | "Login returns 500 when email contains '+' character" |
| Steps | "Try to log in" | "1. Go to /login 2. Enter user+tag@test.com 3. Enter valid password 4. Click Submit" |
| Expected | "Should work" | "User is authenticated and redirected to /dashboard" |
| Actual | "Doesn't work" | "Server returns HTTP 500. Response body: {error: 'invalid_parameter'}. Console: no client-side errors." |
| Environment | (missing) | "Chrome 122, macOS 14.3, staging env, build #4521" |
The bad report requires a conversation before anyone can start investigating. The good report lets the developer reproduce and start debugging immediately.
The Bug Report Title
The title is the most important line. In triage meetings, the team often sees only titles. A good title describes the bug, not the feature.
Title Formula
[What happens] when [condition/trigger]
Examples:
- "Login returns 500 when email contains '+' character"
- "Cart total shows $0.00 after applying 100% discount code"
- "Profile image upload silently fails for files larger than 5MB"
- "Search results page shows infinite spinner on empty query"
Anti-patterns:
- "Bug in login" (what bug?)
- "URGENT: production issue!!!" (urgency goes in priority field)
- "Test case TC-AUTH-007 failed" (what actually happened?)
Attachments That Accelerate Fixes
The right attachment can cut investigation time from hours to minutes.
Screenshots with Annotations
Do not just screenshot the entire screen. Annotate:
- Circle or arrow pointing to the broken element
- Highlight error messages
- Include the URL bar so the developer knows the exact page
Tools: macOS Screenshot (Cmd+Shift+4), Snagit, Lightshot, browser DevTools screenshot.
Video Recordings
For complex multi-step flows where screenshots are insufficient:
- Keep videos under 60 seconds
- Narrate if possible ("Now I click Submit, and you can see the error appears...")
- Trim the beginning and end — start just before the bug trigger
Tools: Loom, macOS screen recording (Cmd+Shift+5), OBS Studio.
HAR Files and Network Logs
For API-level issues, a HAR (HTTP Archive) file captures every network request:
- Open Chrome DevTools > Network tab
- Reproduce the bug
- Right-click in the network tab > "Save all as HAR with content"
- Attach the .har file to the bug report
Console Logs
Copy-paste the actual console output. Do not paraphrase.
Console output:
Uncaught TypeError: Cannot read properties of undefined (reading 'map')
at UserList.render (UserList.jsx:42)
at processChild (react-dom.js:1234)
cURL Commands
For API bugs, provide a curl command that reproduces the issue directly:
curl -X POST https://staging.example.com/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "user+tag@test.com", "password": "ValidPass123!"}'
# Returns: HTTP 500 {"error": "invalid_parameter"}
This lets the developer reproduce without touching the UI.
Isolation: Narrowing Down the Bug
Before filing, try to narrow the scope. The narrower your report, the faster the fix.
Questions to Ask Yourself
- Browser-specific? Try in Chrome, Firefox, Safari. If it only happens in one, note that.
- Environment-specific? Does it happen in staging and production, or just staging?
- Data-specific? Does it happen with any email, or only emails with special characters?
- Timing-specific? Does it happen every time, or intermittently?
- Permission-specific? Does it happen for all users, or only certain roles?
Intermittent Bugs
These are the hardest to report. For intermittent bugs:
- State the reproduction rate: "Reproduces approximately 3 out of 10 attempts"
- Describe what you tried that did NOT trigger the bug
- Note any patterns: "Seems to happen more often right after deployment"
- Include timestamps of occurrences so the team can check logs
Bug Report Workflow
Filing
- Search for duplicates first. Duplicate reports waste everyone's time.
- File one bug per report. Do not combine "login fails AND the forgot password link is broken."
- Assign to the correct team or component. If unsure, assign to the triage queue.
After Filing
- Watch for developer questions. Respond within hours, not days.
- If asked to provide more information, update the bug report itself (not just the comment thread).
- If you discover additional reproduction steps or a simpler reproduction path, update the report.
Verification
When the fix is deployed:
- Reproduce using the original steps — the bug should be gone.
- Test related scenarios — did the fix introduce a regression?
- Close the bug report with a comment: "Verified fixed in build #4530."
Writing Bug Reports Under Pressure
In production incidents, you may need to file a bug report in 2 minutes. Use this minimal template:
Title: [What breaks] when [trigger]
Environment: Production, [timestamp]
Steps: [minimal path]
Actual: [what happened, include error codes]
Impact: [who is affected, how many users]
You can add details later. The priority is getting the information to the right people fast.
Practical Exercise
Find a real bug in any public website (accessibility issues count). Write a bug report using all five essential fields. Then:
- Have a colleague try to reproduce from your report alone (without asking you questions)
- If they cannot reproduce, your report needs more detail
- If they can reproduce in under 2 minutes, your report is effective
Key Takeaways
- A bug report must enable reproduction in under two minutes
- Include all five fields: environment, steps, expected, actual, severity/priority
- The title should describe the bug, not the feature: "[What happens] when [condition]"
- Attach evidence: annotated screenshots, HAR files, console logs, curl commands
- Isolate before filing: narrow down browser, environment, data, and permissions
- Respond quickly to developer questions — a stale bug report gets deprioritized