Most issues are missing half the information needed to fix them. A vague title, no reproduction steps, no context - and then surprise when it sits in the backlog for months.
Here are four things that turn a useless issue into one that gets picked up, understood, and resolved.
1. Write a searchable title
The title is the first thing someone sees in a list of 200 issues. It’s also what shows up in search results. A good title tells you what’s broken without opening the issue.
Bad titles: - “Login broken” - “Fix bug” - “It doesn’t work”
These tell you nothing. You can’t search for them, you can’t triage them, and you’ll end up with five duplicates because nobody can find the original.
Good title: - “OAuth redirect fails when authenticating with passkeys”
This is specific, searchable, and describes the actual behavior. Someone experiencing the same problem will find this issue instead of creating a duplicate.
The test: If someone reads only the title in a notification email, can they understand what the issue is about? If not, rewrite it.
2. Add steps to reproduce
“Login is broken” is not a bug report. It’s a cry for help. A developer reading that has no idea where to start.
Steps to reproduce turn a complaint into an actionable investigation:
1. Go to /users/sign_in
2. Click "Sign in with passkey"
3. Authenticate with biometrics
4. OAuth callback is never triggered
Each step should be concrete and sequential. Include URLs, button names, and exact actions. If the bug only happens under certain conditions (specific browser, specific role, specific data), say so.
The test: Could someone who has never seen this bug follow your steps and hit it on their first try? If not, add more detail.
3. State expected vs actual behavior
This is the most skipped section in bug reports, and it’s the one that saves the most time.
Without it, the developer has to guess what you think should happen. Sometimes the “bug” is actually intended behavior. Sometimes the expected behavior is ambiguous. Spelling it out eliminates that guesswork.
Expected: After passkey auth, browser redirects to the OAuth callback URL with an authorization code.
Actual: Browser stays on the GitLab dashboard. Callback URL is never hit. No error shown.
The gap between expected and actual is literally the bug. When you write it this way, you’ve already done half the debugging work - you’ve isolated what goes wrong and where.
Bonus: Include environment details that might matter. Browser and version, operating system, GitLab edition (SaaS vs self-managed), and whether it’s reproducible every time or intermittent.
4. Add labels and context
Labels are how your team triages without reading every description. A well-labeled issue gets routed to the right person faster.
At minimum: - Type - bug,
feature, or maintenance -
Component - which part of the system is affected
(authentication, CI/CD, API) -
Severity - how bad is it? GitLab uses scoped labels
like severity::1 through severity::4
If your project uses milestones, assign one. If you know who should look at it, assign them. If there’s a related issue or merge request, link it.
The goal: someone scanning the issue list should be able to understand priority, area, and type without opening a single issue.
Why this matters
A well-written issue respects everyone’s time. The reporter spends five extra minutes writing it properly. The developer saves thirty minutes not asking clarifying questions. The PM can triage it in seconds instead of minutes.
Multiply that across a team, across hundreds of issues, and the compound effect is massive.
Write issues like someone else has to fix them - because they do.