What This Template Is For
Bad bug reports waste engineering time. "The app is broken" tells an engineer nothing. A good bug report tells them exactly what happened, what should have happened, how to reproduce the problem, and how urgent it is. The difference between a two-hour fix and a two-day investigation is often just the quality of the bug report.
This template gives your team a consistent format for documenting bugs. It covers every field an engineer needs to diagnose and fix the issue: severity classification, environment details, step-by-step reproduction, expected vs. actual behavior, and visual evidence. It works for customer-reported bugs, QA-discovered defects, and issues caught during code review. The Technical PM Handbook covers how product managers should work with engineering on bug triage and resolution workflows.
Using this template also creates an audit trail. When someone asks "how many critical bugs did we ship last quarter?" or "what is our mean time to resolve P0 issues?", a consistent bug tracking format makes that data queryable. Without it, every bug report is a snowflake and aggregate analysis is impossible. For teams managing bugs alongside feature work in the same workflow, the Sprint Planning template shows how to allocate capacity for unplanned work.
When to Use This Template
- When a customer reports an issue. Support reps should fill out this template immediately, not paraphrase the problem in a Slack message to engineering.
- When QA finds a defect during testing. Capture it in this format before the sprint review so the team can assess severity and decide whether to fix before release.
- When an engineer discovers an issue in code review. If the issue exists in production or will be deployed soon, document it formally rather than leaving a PR comment.
- When monitoring or alerting catches an anomaly. Automated alerts (error rate spikes, latency increases, failed jobs) should be investigated and, if confirmed as bugs, documented here.
- When a regression is identified after a deployment. Regressions need immediate documentation so the team can decide whether to hotfix, rollback, or schedule a fix.
- During post-incident review. After resolving a production incident, create bug reports for any underlying defects that contributed to the incident.
How to Use This Template
Step 1: Fill in the Basics
Record the title, reporter, date, and environment. The title should be specific enough that an engineer can understand the bug without opening the report. "Login fails" is too vague. "Login button returns 500 error on mobile Safari when password contains special characters" is actionable.
Step 2: Classify Severity
Use the four-level severity scale in the template. Be honest about severity. Calling every bug "Critical" desensitizes the team and delays actual critical issues. If the bug has a workaround and affects fewer than 5% of users, it is Medium, not Critical. The Product Operations Handbook covers how to establish severity definitions that your entire organization agrees on.
Step 3: Write Reproduction Steps
This is the most important section. List every step from a clean starting state to the point where the bug appears. Include specific data (the exact email address, the file size, the browser version). If the bug is intermittent, note the approximate frequency ("Reproduces ~3 out of 10 attempts"). An engineer who cannot reproduce the bug cannot fix it efficiently.
Step 4: Document Expected vs. Actual Behavior
State what should happen and what actually happens. Be precise. "The page should load" is vague. "The dashboard should display the user's 30-day activity chart within 2 seconds of page load" is testable. Include screenshots, screen recordings, or console logs whenever possible.
Step 5: Submit and Track
Submit the bug report in your team's tracking tool (Jira, Linear, GitHub Issues). Tag it with the appropriate severity label and assign it to the triage queue. Do not assign it directly to an engineer unless you are the engineering lead. Triage is the team's decision, not the reporter's.
The Template
Bug Report
Bug ID: [BUG-001]
Bug Title: [Clear, specific description of the defect]
Reporter: [Name, role]
Date Reported: [YYYY-MM-DD]
Status: [New / Triaged / In Progress / Fixed / Verified / Closed / Won't Fix]
Severity
| Level | Definition |
|---|---|
| Critical (P0) | System down, data loss, security vulnerability, or complete feature failure affecting all users. No workaround exists. Requires immediate fix. |
| High (P1) | Major feature broken for a significant portion of users. Workaround exists but is painful or unreliable. Fix within current sprint. |
| Medium (P2) | Feature works but produces incorrect results, poor UX, or performance degradation for some users. Workaround is acceptable. Fix within 1-2 sprints. |
| Low (P3) | Cosmetic issue, minor inconvenience, or edge case affecting very few users. Fix when capacity allows. |
This bug's severity: [P0 / P1 / P2 / P3]
Justification: [1 sentence explaining why this severity level]
Environment
| Attribute | Value |
|---|---|
| Product version | [e.g., v2.4.0, build #1847] |
| Browser / Client | [e.g., Safari 17.3, Chrome 122, iOS app v3.1.2] |
| Operating system | [e.g., macOS 14.3, iOS 17.3, Windows 11, Android 14] |
| Device | [e.g., iPhone 15 Pro, MacBook Air M2, Samsung Galaxy S24] |
| Account type | [e.g., Free, Team, Enterprise] |
| Environment | [Production / Staging / Local dev] |
| Network | [WiFi / Cellular / VPN / Corporate proxy] |
Steps to Reproduce
- [Start from a clean state: logged out, fresh browser, specific account type]
- [Navigate to specific page or trigger specific action]
- [Enter specific data or interact with specific element]
- [Continue with exact steps until the bug appears]
- [Note the point where expected and actual behavior diverge]
Reproducibility: [Always / Intermittent (~X out of 10 attempts) / Once (could not reproduce again)]
Expected Behavior
[Describe exactly what should happen at step N. Be specific enough that someone unfamiliar with the feature can verify whether the bug is fixed.]
Actual Behavior
[Describe exactly what happens instead. Include error messages (exact text), HTTP status codes, console errors, or unexpected UI states.]
Screenshots / Recordings
[Attach or link to:]
- ☐ Screenshot of the error state
- ☐ Screen recording showing the reproduction steps
- ☐ Browser console logs (if applicable)
- ☐ Network tab output (if applicable)
- ☐ Server logs (if available)
Workaround
[Describe any temporary workaround for users. If none exists, write "None identified." If the workaround is complex, note it here so support can share it with affected users.]
Impact Assessment
| Factor | Detail |
|---|---|
| Users affected | [All users / Segment / Estimated count or percentage] |
| Revenue impact | [Blocked transactions, broken billing, at-risk accounts] |
| Support ticket volume | [Number of related tickets or complaints] |
| Regression? | [Yes: introduced in version X.Y.Z / No: has always existed / Unknown] |
Resolution
Assigned to: [Engineer name]
Target fix date: [YYYY-MM-DD or Sprint number]
Root cause: [To be filled by engineering after investigation]
Fix description: [To be filled after the fix is implemented]
PR / Commit: [Link to the fix]
Verified by: [QA name, date verified]
Deployed to production: [Date]
Filled Example: Payment Processing Failure on Mobile Safari
Bug Report
Bug ID: BUG-2847
Bug Title: Checkout payment submission returns "Payment Failed" on Mobile Safari when billing address contains an apartment number
Reporter: Lisa Park, Customer Support Lead
Date Reported: 2026-02-15
Status: Fixed
Severity
This bug's severity: P0 (Critical)
Justification: Payment processing is a core revenue flow. 100% of affected users cannot complete checkout. No workaround exists on mobile.
Environment
| Attribute | Value |
|---|---|
| Product version | v2.3.8 (production) |
| Browser / Client | Safari 17.3 on iOS 17.3.1 |
| Operating system | iOS 17.3.1 |
| Device | iPhone 15, iPhone 14 Pro, iPhone 13 (confirmed on all three) |
| Account type | All account types (Free trial and paid) |
| Environment | Production |
| Network | WiFi and Cellular (both affected) |
Steps to Reproduce
- Open the app in Mobile Safari on iOS 17.x (not the native app).
- Log in with any account that has items in cart.
- Navigate to Checkout.
- Enter a billing address that includes an apartment, suite, or unit number in the Address Line 2 field (e.g., "Apt 4B", "Suite 200", "#12").
- Enter valid card details (test card: 4242 4242 4242 4242, any future expiry, any CVC).
- Tap "Complete Purchase."
- Observe: a red banner appears with "Payment Failed. Please try again or contact support." The payment is not processed. The order remains in cart.
Reproducibility: Always (10 out of 10 attempts when Address Line 2 is filled. Works correctly when Address Line 2 is left blank.)
Expected Behavior
After tapping "Complete Purchase" with a valid card and valid billing address (including Address Line 2), the payment should process successfully. The user should see an order confirmation page with order number and receipt.
Actual Behavior
The payment form submits but the Stripe API call fails. The UI displays "Payment Failed. Please try again or contact support." The browser console shows: TypeError: Cannot read properties of undefined (reading 'trim') at formatAddress (checkout.js:847:23). The Stripe API is never called because the client-side address formatting function crashes before constructing the payment intent request.
Screenshots / Recordings
- Screenshot: [payment-failed-safari.png] showing the error banner
- Console log: [console-log-checkout-error.txt] showing the TypeError stack trace
- Screen recording: [safari-checkout-bug.mp4] showing full reproduction from cart to error (45 seconds)
- Stripe dashboard: no payment intent created for any of the test attempts (confirming the API call never fires)
Workaround
Users can complete checkout by leaving the Address Line 2 field blank and including the apartment number in Address Line 1 (e.g., "123 Main St Apt 4B"). This workaround has been shared with the support team for customer-facing use. Desktop browsers (Chrome, Firefox, Safari on macOS) are not affected.
Impact Assessment
| Factor | Detail |
|---|---|
| Users affected | Estimated 12% of mobile web checkout attempts (based on analytics showing 12% of users fill in Address Line 2) |
| Revenue impact | ~$8,400/day in failed mobile transactions (based on average order value and mobile checkout volume) |
| Support ticket volume | 23 tickets in the last 48 hours referencing "payment failed" on mobile |
| Regression? | Yes. Introduced in v2.3.8 (deployed Feb 13). The formatAddress function was refactored in PR #1923 and the Address Line 2 null check was removed. v2.3.7 did not have this issue. |
Resolution
Assigned to: David Kim, Senior Backend Engineer
Target fix date: 2026-02-16 (hotfix)
Root cause: PR #1923 refactored the formatAddress() utility and removed the null/undefined check for addressLine2 before calling .trim(). On Mobile Safari, the form serializer returns undefined for empty optional fields instead of an empty string (Chrome returns ""). The .trim() call on undefined throws a TypeError that is caught by the payment form's generic error handler and displayed as "Payment Failed."
Fix description: Added null coalescing (addressLine2 ?? '') before the .trim() call. Added unit tests for all optional address fields with undefined, null, and empty string values. Added Safari-specific integration test.
PR / Commit: PR #1941, commit a3f7c2e
Verified by: QA Lead Tomas Hernandez, verified Feb 16 on Safari 17.3 (iPhone 15 and iPhone 13) and Safari 17.2 (iPhone 14 Pro). All Address Line 2 variations tested: "Apt 4B", "Suite 200", "#12", empty, null.
Deployed to production: Feb 16, 2026, 2:15 PM UTC (hotfix release v2.3.9)
Key Takeaways
- Write bug titles that an engineer can understand without opening the report. "Checkout payment submission returns 'Payment Failed' on Mobile Safari when billing address contains an apartment number" is a good title. "Payment broken" is not.
- Severity classifications must be consistent across your team. Agree on definitions during onboarding, not during an incident. If your team does not have shared definitions, start with the four-level scale in this template.
- Steps to reproduce are the highest-value section of any bug report. Invest the time to make them exact. Include specific data, specific browser versions, and specific account states. The Technical PM Handbook explains how PMs can develop the technical fluency to write better reproduction steps.
- Always check whether a bug is a regression. If the feature worked in a previous version, identifying the commit that broke it cuts investigation time significantly.
- Track impact in business terms, not just technical terms. "12% of mobile checkout attempts fail" is more actionable than "TypeError in formatAddress." It tells leadership and the team why the fix is urgent.
- Close the loop after resolution. Update the bug report with the root cause, fix details, and verification status. This creates a searchable knowledge base for future debugging.
