Project Management

What do you mean by bug? Explanation, kinds, and how to…

— Nesha Zoric

Short answer: A software bug is any gap between what a program is supposed to do and what it actually does. A mistake in code, design, or specification that produces the wrong behaviour. The categories that pull their weight are logic, syntax, runtime, resource, and concurrency bugs. The separation that pulls its weight is severity (how bad it is for the user) versus priority (how soon we fix it). Triage is where most teams fail. Not finding bugs, but deciding what to do with them.

A software bug is the difference between what a piece of software is expected to do and what it actually does. All done. An error in the code, design or specification that generates behaviour that nobody wanted. All the rest is footnotes to this.

This question is asked a thousand times a month because the definition is easy and the practice is hard. Understanding the definition of a bug can be stated in one sentence. It takes a career to know which bugs to fix and which to ignore, who writes the bug report, severity vs priority categorisation, and whether the bug gets story points at all. This guide is your lunchtime version of that career a human can read.

The upcoming segment will elaborate on the exact definition. We further dig into the story behind the name. Most people are familiar with Grace Hopper’s famous moth incident but few seem to get it right. We’ll then explore the 5 types of bugs you actually see on a working team. All teams seems to get wrong is the difference between severity and priority. After that, we’ll examine the bug life cycle from report to resolved. Finally, we will get to the part most PM-tool vendors won’t tell you out loud: when it’s actually correct to not fix a bug at all.

A software bug, plainly

A software bug refers to any defect in the software that makes it behave differently from how it should. That sentence is helping “should” do heavy lifting. The specification, user story, or design defines the behavior that should happen. In their absence, it is defined by what a “reasonable” user would expect the system to do. That's a bug if the program does anything else.

The industry has a few other words for the same thing: defect, fault, error, failure, glitch, issue, anomaly. The official norms get nitpicky with them. The IEEE/ISO 24765 vocabulary recognize the difference between a fault (the actual problem in the code) and a failure (the visible problem to the user). In everyday engineering life, hardly anyone honors that distinction. And having just one word that everyone understands works better than having three words where half the team uses them backward.

A bug should not be

  • A feature nobody built yet. "I can't export to CSV" is not a bug if CSV export was never in scope. It's a feature request wearing a bug costume. Teams who log those as bugs quietly inflate their defect numbers and lose the signal — the same miscategorisation we unpack in bugs and chores: estimate, estimate.
  • A difference of taste. "The button should be blue" is a design discussion, not a bug — unless the spec said the button should be blue and it isn't.
  • A change in requirements. "We decided we want it to work the other way now" is a new story. The code is doing exactly what it was asked to do; the ask changed.

The useful test is: was there a stated or reasonable expectation, and does the software fail to meet it?* If that’s the case, bug. An unstated expectation is essentially a request, barring unreasonable ones. A new story begins if the expectation changes.

Where the word "bug" came from (and the moth story is misleading)

A brief backstory, since it's used so much in interviews.

The term "bug" meaning technical defect came into use seventy years ago. In 1878, Thomas Edison used it in messages referring to faults in his inventions. The first programmable computers were built when this term was already commonly used by engineers.

People get the history wrong around the famous incident in 1947 at Harvard that involved Grace Hopper and a moth. Hopper's team discovered a real moth lodged in a relay of Mark II computer. They removed it, taped it in the logbook and wrote that it was “first actual case of bug”. The humour works only due to the existence of the term the engineers were being witty. The word’s origins are not found in the story of a moth housed at the Smithsonian (the logbook page is online). The story is a good one. It is not the origin story.

It is important to remember that the word “bug” is a borrowed metaphor from mechanical engineering. It is an object that interferes with the functioning of a machine. It’s more useful to think that you don’t write bugs on purpose, they get in through gaps in your attention. When we view non-shipped bugs as moral failures, they become piles of shame, not queues to be worked through.

The five kinds of bugs you'll actually see

When it comes to lists of bug types, the internet is awash with twenty-entry lists, three of whose entries are padding. Five distinct castes, which are derived from the practical work of writing and shipping code.

  1. Logic errors. The code runs without crashing but computes the wrong thing. A tax calculator that adds VAT to the pre-tax total instead of the post-discount total. The hardest to catch, because the program looks healthy from the outside and the tests pass if the tests encode the same misunderstanding as the code. Discovered mostly by users or by someone eyeballing the output.
  2. Syntax errors. The code doesn't compile or parse. Missing bracket, wrong keyword, typo in a function name. In compiled languages, you catch these before the program ever runs; in dynamic languages, you catch them when the branch of code that contains the typo finally executes in production at 2am. (Reader: use a linter.)
  3. Runtime errors. The code compiles, runs, and then throws — null reference, divide-by-zero, index out of range, file-not-found. These are the easy ones to triage because the stack trace tells you where to look. They become hard only when the trace points at code far from the actual cause (classic null-pointer-eight-frames-after-the-null-came-in).
  4. Resource bugs. Memory leaks, file handles not closed, database connections never returned to the pool, event listeners that pile up forever. The program works for an hour and gets slower, then it works for a day and crashes. These are brutal to reproduce because they only appear under load or over time, and both of those are expensive to simulate.
  5. Concurrency bugs. Two threads, two processes, or two instances of the same request stepping on each other. Race conditions, deadlocks, duplicate writes, lost updates. The signature is "it only happens sometimes," which really means "it happens whenever the scheduler feels like it, which looks random from the outside". Hardest to debug because the thing that reveals the bug is interleaving, and you can't put interleaving in a stack trace. Property-based and generative testing is the practical tool for shaking these out.

Engineers working in the industry are likely to see all five by the third year. Anytime you hear someone tout a 6th category of bug that goes “integration bug” or “usability bug” or “performance bug” you can usually classify it as one of the five above in different words. Performance bugs often stem from issues related to resource management. Integration bugs frequently involve concurrency or logic errors that affect communication across different components or systems.

Severity and priority are not the same thing

One common mistake that happens in bug triage is equating severity with priority as the same number.

  • Severity is how bad the bug is for the user when they hit it. The data loss. The crash. The security hole. Severity doesn't care how many users are affected.
  • Priority is how soon we fix it. Priority cares about everything — severity, frequency, visibility, business cost, whether the fix is cheap, whether the workaround is tolerable, whether the next release is tomorrow or next month.

A one-time crash that wipes out a customer’s unsaved form is high severity. If three users a year experience it, and workaround is “press back”, it is likely medium priority.

Typo in the “About” page is of low severity. Typo in your company name, on the day of your Series A announcement – highest priority.

Teams that conflate the two axes into one will either (a) fix cosmetic issues first because the cosmetic issue is in front of the CEO before they fix data loss bugs; or (b) ignore real data loss bugs because they happen quarterly. A triage system with two axes, which assigns low, medium, and high values to both severity and priority, will comfortably fit on a whiteboard. Furthermore, it’s enough to survive first contact with the reality of backlog grooming.

The 2x2 matrix is the least complex tool that is functioning. People desire more advanced frameworks. No one makes use of it after the second week.

The bug lifecycle, from report to resolved

Most teams actually implement a workflow with six states rather than the twelve-state Jira workflow.

  1. Reported. Someone noticed. The report lands in the queue.
  2. Triaged. An anchor or PM reads the report, confirms it's a bug (not a feature request or a config issue), and sets severity + priority.
  3. Reproducing. An engineer tries to make it happen on purpose. If it reproduces, it moves forward. If not, it goes back to the reporter for more detail or gets closed as "cannot reproduce," a legitimate close state that teams under-use.
  4. In progress. Someone is fixing it.
  5. In review / verifying. The fix is written. Code review, QA, or the original reporter confirms the behaviour is gone.
  6. Resolved. Shipped, verified, closed.

These are six states. If a team's story count exceeds six, the team's "config engineer" pays a fee to Jira, not the estimation team. The statuses that are frequently added on to (waiting for information, rejected, won’t fix, duplicate, reopened) are all one of the above six with a label or comment. Unless the size warrants it, don’t provide them separate statuses, and for all teams it doesn’t. Teams that automate the “reported” step with crash reporters and HAR uploads tend to spend less time entering data and more time fixing the pattern we saw in six third-party tools for automatic bug creation.

LiteTracker is constructed according to precisely this design. When a bug enters the queue, it doesn't earn any story points. It gets set to work on like any other piece of work. As a result, the velocity number is only counting delivered user value. Bug fixes don't fall into this category. A fix is getting back on solid footing that you were or should have been on. We elaborate on the significance of this in.

How to write a bug report that doesn't waste the engineer's time

6 Areas. “a bug report has more than this, the extras are usually filler.” If there are fewer materials than needed, the engineer will come to find you.

  • Summary. One sentence. "Login fails silently on Safari 17 when password contains apostrophe." Not "login doesn't work".
  • Steps to reproduce. Numbered. Specific. Include the input values. "1. Open /login. 2. Enter user [email protected] and password o'brien1. 3. Click submit." If you can't produce steps, say so. "Intermittent, happens roughly once per ten sessions" is useful; "doesn't work" is not.
  • Expected result. What should have happened.
  • Actual result. What did happen. Include error text verbatim if there is any.
  • Environment. Browser, OS, device, build number, logged-in user ID (never a password). If only one of those matters, say so.
  • Attachments. Screenshot, HAR file, server log excerpt. Attach the thing the engineer would ask for next if they were in the room.

A report that contains these 6 fields can be triaged in less than a minute. A report is a dialogue without them. A team that communicates their issues effectively will fix bugs in half the time compared to a team that constantly opens an issue with "doesn't work on my phone." They are not superior engineers. As they are not asking the same four questions again and again on every ticket. The QA team’s perspective on the same lifecycle and what that looks like in a working day is in a day in the life, testing on the Tracker team.

Why bugs happen — the three root causes most teams don't fix

The superficial response is "we hurried." The more profound response is nearly always one of three.

  • Missed states. The code handles the happy path and one or two obvious failure modes, and nothing else. The user does something nobody imagined (enters emoji in a numeric field, hits back after submitting, loses network mid-upload) and the code has no answer. Fix: lean harder on property-based tests and on walking the state machine deliberately in design review.
  • Unspoken assumptions. Two engineers each wrote code that was correct given what they thought the other side was doing. Classic integration bug. Fix: write the contract down. API spec, schema, or at minimum a one-page document that both sides reference.
  • Scope creeping past the test coverage. A feature grew in six small commits, and the tests were written against the first commit. The code works for the original intent and quietly breaks on the five extensions. Fix: when a feature grows mid-flight, pay the test tax before merging the extension, not after.

When teams view bugs as individual incidents, the bug shipping rate remains constant. When teams make it a practice to read all five of the latest bug reports, and ask themselves “what root cause ties these together,” they start to ship less. Addressing 20% of causes that lead to 80% of bugs is the entire approach. LiteTracker uses the same principle in their product design, that is, focussing on the 20% of PM features that generate 80% of aggressive results. It is essentially the other 80% that brings enterprise PM tools to their knees. In why it's easier for product teams to cram features and bugs into each release instead of cutting back, we analyzed the dynamic between release pressure and root cause that keeps them alive.

When NOT to fix a bug

The standard response is to fix the bug. at times, it is not the right one

Don't mend a bug unless.

  • The cost of the fix is higher than the cost of the bug. A once-a-year display glitch that nobody has reported except internal QA. Document it, keep the ticket open as a known issue, move on. There's a reason major vendors ship with hundreds of open bugs on release day — most of them are below the fix-cost line.
  • The bug is in a feature that's being deprecated. Fixing a bug in a module you're about to delete is spending the budget twice. Note it, don't fix it, delete the module on schedule.
  • The user has adapted. Occasionally (rarely, but it happens) a bug has lived long enough that a nontrivial fraction of users are relying on the buggy behaviour. Fixing it will cause more support tickets than ignoring it. The honest move is to design the "correct" behaviour as a new feature and let the old behaviour deprecate on its own schedule. If this one feels controversial, it should. It's the one bug-triage opinion most teams won't say out loud.

The anti-pattern consists of regarding every bug as a must-fix. Triage inputs must be bugs and not moral debts. The group that addresses every reported bug in sequential order will overlook the two actual critical bugs.

Frequently asked

What is a software bug in simple terms?

The difference between what software should do and what it actually does is a defect. If the specification states one thing and the code behaves differently, it is a bug.

What's the difference between a bug and a defect?

The need for anything specific. Standards (IEEE/ISO 24765) sometimes separate a “fault” (the cause in the code) from a “defect” or “failure” (the user-visible result). In practice, almost no team outside of a regulated industry respects the split. Stick to one word and keep going.

What are the most common types of software bugs?

Five types address nearly all software bugs: logic errors, syntax errors, runtime errors and resource bugs (also known as memory leaks) and concurrency bugs (also known as race conditions) Performance glitches and integration glitches typically fall under one of these five issues which cross a boundary.

What causes software bugs?

Three recurring root causes we see: missed states (code only handles the happy path), unvoiced assumptions about integrating modules, and scope creeping past the test coverage. The phrase "We rushed" merely describes a symptom, not the real root cause.

How are bugs reported and tracked?

The six fields contained in a good bug report include summary, steps to reproduce, expected result, actual result, environment and attachments. The states can be anything but they specifically track them through a lifecycle of states- reported, triaged, reproducing, in progress, in review, resolved. A situation where there are more states than that has arisen through tooling eating the team.

Should bugs earn story points?

No. Points evaluate the newly delivered value for users. A bug fix is addressing a problem the team was meant to have already solved. Calling bugs inflates velocity to a fiction and quietly rewards teams for shipping defective work in the first place.

What's the difference between bug severity and priority?

The severity of a flaw is determined by the degree of impact it has on a user when experiencing it. The order in which we fix something is known as priority. Frequent occurrence, high cost of business, and availability of workarounds are factored in to roadmap a solution. The most common triage mistake is collapsing them into one number.

Can software ever be bug-free?

In reality, no codebase, apart from a trivial one, can be without a bug. We are not targeting zero bugs; we are targeting zero bugs above a severity threshold that will make it ship. The rest get an honest triage and get either fixed, documented, or accepted as-known issues.

Still stuck

The triage gives a real answer to the question, “What is a software bug?” not the definition. Teams that do clean releases are those that have a separation of severity from priority, limit the work in progress to 6 states and stop giving story points to bug fixes. Thus velocity has meaning again.

That is the foundation of LiteTracker. The bugs are not tracked as anything pointable work, and the queue is purposely boring, featuring six states, two axes, no twelve-stage workflow. You do not need a credit card or demo call to use the free plan. If a shared sheet and Discord thread is currently better for your bug flow, use those instead; we’d rather you not pay us for friction you don’t have.

Having less than 3 engineers means you possibly do not need a bug tracker at all – just a pinned message in the team channel and once-a-week 20 min triage takes you a long way. Return later if there is a delay.