A bug report has one job: get a fix shipped. Everything between “something is wrong” and “it’s fixed” is overhead, and a vague report is where most of that overhead hides. The engineer reads it, can’t reproduce the problem, asks a clarifying question, waits a day for the answer, asks another, and a five-minute fix turns into a week of back-and-forth across three time zones.
The fix for that isn’t more process. It’s a report that contains everything the next person needs and nothing they don’t. Here’s what that looks like, and a template you can paste into your tracker right now.
What a bug report is actually for
A bug report is two things at once, and the best ones keep them distinct:
- A reproduction recipe. Enough for someone who isn’t you, on a different machine, to make the bug happen on purpose. If they can reproduce it, they can fix it and then prove it’s fixed.
- A decision input. Enough for whoever triages to decide how much this matters and when to deal with it — without scheduling a meeting to find out.
Most bad reports fail at the first and skip the second entirely. “The export is broken 😡” is neither a recipe nor a decision input. It’s a feeling. The engineer can’t act on a feeling.
The anatomy of a report someone can act on
You don’t need a fifteen-field form. You need these, in roughly this order.
A specific title
The title is the one part everyone reads and most people search later. Make it describe the symptom, specifically.
- Bad: “Export broken”
- Better: “CSV export fails”
- Good: “CSV export of >10k rows times out with a 504”
Write it so that six months from now, someone hitting the same problem finds this report instead of filing a duplicate. Specific titles are also what search engines and AI assistants surface when a developer pastes the error into a chat — vague ones disappear.
Tip: write the title last. Once you’ve described the bug, the precise title is obvious.
Environment and context
Bugs live in a context. Capture the parts that could plausibly matter:
- Where it happened — production, staging, local; which URL or screen.
- Client details — browser and version, OS, device, app version or build.
- Who it happened to — a specific user or account, a role, a plan tier. (Use an ID, not a name, if the data is sensitive.)
- When — a timestamp, ideally with a timezone, so logs can be correlated.
You won’t know in advance which of these is the cause. Include the ones that are cheap to capture; the engineer will thank you when the bug only reproduces on Safari, or only for accounts created before a certain migration.
Steps to reproduce
This is the heart of the report. Number the steps. Start from a known state. Make them minimal — strip out everything that isn’t required to trigger the bug.
1. Log in as a member (not an admin).2. Open a project with more than 10,000 entries.3. Click "Export → CSV".4. Wait.If you can’t reproduce it reliably, say so explicitly — “happens roughly 1 in 5 attempts” is vital information, not a failure. Intermittent and deterministic bugs get investigated completely differently.
Expected vs. actual
State both, even when the gap seems obvious to you. The contrast is what turns “it’s broken” into a defined defect.
- Expected: A CSV file downloads within a few seconds.
- Actual: The request hangs for ~60s, then returns a 504. No file downloads.
“Obvious to you” and “obvious to the person fixing it” are different things. Spelling out the expected behavior also surfaces the cases where the real bug is a misunderstanding — sometimes the software is right and the expectation was wrong, and that’s worth finding out before anyone writes code.
Evidence
Attach what you have: a screenshot or screen recording, the exact error message (as text, so it’s searchable — not only a screenshot), relevant log lines, a request ID, a stack trace, the network response. Evidence is what lets an engineer skip the “can you confirm…” round-trip entirely.
A request ID or correlation ID is worth ten screenshots. It’s the thread that ties the user’s experience to what the server actually did.
Severity and priority — and why they’re not the same
These two get conflated constantly, and conflating them leads to either everything being “urgent” or real fires being missed. (They’re worth a deeper look on their own — see severity vs priority.)
- Severity is about impact: how bad is it when it happens? Data loss is high severity. A misaligned icon is low severity.
- Priority is about order: when should we deal with it relative to everything else?
They’re related but independent. A typo on the pricing page is low severity but might be high priority — it’s costing sales today. A crash that only affects an internal admin tool used twice a year is high severity but low priority. As the reporter, your job is to describe severity honestly (you know the impact) and suggest a priority. The final priority call belongs to whoever triages, because only they can see it against everything else in the queue.
The template
Paste this into your tracker — or save it as an issue template — and fill it in. It’s deliberately short. A template people actually complete beats a thorough one they skip.
## Summary
<One sentence: the specific symptom.>
## Environment
- Where: <prod / staging / local — URL or screen>- Client: <browser + version / OS / device / app build>- Account / user: <ID, role, or plan — if relevant>- When: <timestamp + timezone>
## Steps to reproduce
1.2.3.
## Expected
<What should happen.>
## Actual
<What actually happens. Include the exact error text.>
## Evidence
<Screenshot / recording / logs / request ID / stack trace>
## Severity & suggested priority
- Severity: <low / medium / high — based on impact>- Suggested priority: <your recommendation; triage decides>- Reproducibility: <always / intermittent (~X in Y)>Two reports, side by side
Same bug. One bounces; one gets fixed.
The one that bounces:
CSV export is broken, can someone look at it? It’s been doing this a while. Pretty urgent.
There’s nothing here to act on. Which export? Broken how? On what? “A while” and “pretty urgent” tell triage nothing. This report will cost three messages before any work starts.
The one that gets fixed:
Summary: CSV export of projects with >10k entries times out with a 504.
Environment: Production,
/projects/acme/export. Chrome 128, macOS. Accountorg_3f9a(Pro). 2026-06-03 14:22 UTC.Steps:
- Log in as a member.
- Open a project with >10k entries.
- Click Export → CSV.
- Wait ~60s.
Expected: CSV downloads in a few seconds.
Actual: Request hangs ~60s, returns 504, no file. Error:
upstream request timeout. Request IDreq_88c1d2.Evidence: Screen recording attached; server log lines around 14:22 UTC.
Severity: High (export is unusable for our largest customers). Suggested priority: this sprint. Reproducibility: always.
The second one is maybe ninety seconds more work to write. It can save days.
A few habits that make every report better
- One bug per report. Bundling three issues into one ticket means none of them gets a clean status. Split them.
- Reproduce it once before filing. Half of “bugs” evaporate on the second try — a stale tab, a cached build, a flaky network. Confirming it’s real (and how reliably) is the single highest-value thing a reporter does.
- Search first. A thirty-second search for an existing report saves the duplicate-triage tax. If you find one, add your details to it instead.
- Describe the symptom, not your theory. “The cache is wrong” is a guess; “stale data shows for ~30s after an edit” is an observation. Lead with what you saw. Put your theory at the end, clearly marked as a theory.
- Write for a stranger. The person who fixes this may have never seen the feature. Don’t rely on shared context that lives only in your head or yesterday’s Slack thread.
The real reason most bug reports are bad
Everything above is learnable in about five minutes, which raises an honest question: if writing a good report is this simple, why are most reports so bad?
It isn’t ignorance. It’s economics. The person best positioned to write the report — the one who just hit the bug — is the person least rewarded for writing it well. They’ve already found their workaround; the bug no longer blocks them. A careful report costs them ten minutes now, and almost every cent of the payoff lands on someone else: the engineer who fixes it, the teammate who hits it next month, the stranger who searches the same symptom next year. Cost here, benefit there. That asymmetry — not a skills gap — is why the average report is a one-line shrug.
There’s a second, sneakier tax: a bug report has a short half-life. The precise sequence of clicks, the exact error text, the “oh, I had just toggled that setting” — all of it starts evaporating from the reporter’s memory within minutes. The report written right after the bug is worth several of the one reconstructed the next morning. So the moment you most need someone to write carefully is the moment they’re most eager to move on.
Which means a guide like this one — useful as it is — can’t fix the problem on its own. You will not out-discipline an incentive. What actually moves the needle is making the good report the path of least resistance: the cheapest thing to do at the moment of capture, not the most virtuous. A template that’s already in the box, so the structure is free. A “report a bug” action that captures the URL, browser, build, and last error automatically, so the reporter writes one sentence and the context comes along for nothing. A screen recorder one click away. Every field you can pre-fill is a field nobody has to be persuaded to care about.
That reframes the whole goal. Don’t try to train people into better reports — most of them already could write one. Make a great report take less effort than a bad one. The template above is step one; the rest is tooling that quietly does the work the reporter has no incentive to do.
Why we’re opinionated about this
A good report is mostly about structure — the same few fields, every time, in a shape the next person can scan. That’s not a coincidence with how we think about tooling. The reason trackers feel like paperwork is usually that they ask for the wrong things, or let every report be a different shape, so triage becomes archaeology.
We’re building Bugspot around the bet that a fixed, sensible structure for the work beats infinite configurability — that the constraint is what keeps reports fast to write and fast to act on. This guide is that bet applied to a single ticket: a small, consistent shape that respects everyone’s time. You don’t need Bugspot to use it. Steal the template, and your next report will get fixed faster than your last one.