The worst bug does not break the feature. It breaks the view

9/13/20267 min read
The worst bug does not break the feature. It breaks the view

Direct answer: the hardest bug to find is not the one that breaks a feature — someone reports that immediately. It is the one that breaks the view of the feature: everything works, but the interface says otherwise. It survives for months because whoever has the permissions to notice (the administrator) never walks through the broken code, and whoever would see it (a normal user) reads it not as a fault but as «I must not have configured it properly yet».

TL;DR

  • 26 tools connected, tested live in production against real data. All working.
  • The configuration page showed zero, as if nothing were connected.
  • Cause: the code deciding which tools to show only handled the cases already seen (the known e-commerce platforms). A tool group activated by a different mechanism fell into a branch that did not exist.
  • The same bug was already present for another tool group. Nobody had noticed.
  • Why it survived: whoever configured it had always done so from an admin account, which sees everything by definition and therefore never passes through the broken branch.
  • Operating rule: always test with the least-privileged account, not yours.

The situation

I had just finished connecting 26 tools to a conversational assistant: legal search, PNRR projects, rulings, parliamentary data. I had verified them one by one, live, in production, against real data. They worked.

Then I opened the page where the assistant is configured — the one where you choose which tools to give it — and it showed zero available tools. As if I had connected nothing.

This is the phase where most people lose half a day, because the system is giving you two opposite pieces of information and neither is obviously wrong.

Where the problem was

The code answering «which tools can I show to whoever is configuring this assistant» was written as a series of known cases:

  • if the customer has a shop on one platform → show these tools
  • if they have a shop on another platform → show those
  • if they have a specific configuration → show these others

My tools activated through a different mechanism: a single group, independent of the e-commerce platform, for the simple reason that the product sells nothing. None of the existing branches knew what to do with «this is not a shop».

The result: my group fell into the void. Not an error, not an exception, not a log line. Just an empty list, returned with the same composure a populated list would have been.

The feature was intact. Only the answer to «what is there?» was broken.

The bonus: it was already there, for someone else

Here the story gets interesting. Digging, I found that the exact same bug already existed for another tool group — shipment tracking. Same cause, same missing branch, same symptom.

It had been there for months. Nobody had ever reported it.

The reason is the part worth taking away: whoever had configured that product had always done it with an admin account. And an administrator, by definition, sees everything: the code filtering tools per tenant is not even reached, because an earlier branch says «you are admin, here is everything».

So the two categories of people who could have spotted it were both blind, for opposite reasons:

Who Why they do not see it
Administrator (developers, whoever sets it up) Skips the broken branch: always sees everything
Normal user (the customer) Sees the empty list, but thinks «I have not configured it yet»

The customer does not report a system bug: at most they report their own incompetence — and more often they do not report at all, they give up.

Why this class of bug lives so long

A bug that breaks a feature has a short life: someone tries to do something, it does not work, they say so. Feedback is immediate and unambiguous.

A bug that breaks the view has three properties that make it nearly immortal:

  1. It produces no errors. An empty list is a legitimate answer. No log, no alert, no trace.
  2. It is invisible to developers, because developers run with full permissions.
  3. It is read as the user's own fault by whoever hits it, so it never escalates.

Add that automated tests, where they exist, are almost always written with the most convenient test user — the one with every permission — and you have a gap that preserves itself.

What I do now

  • The critical path is tested with the least-privileged account that exists. Not yours. If your application has roles, the acceptance test runs on the lowest role that must be able to do that thing.
  • An empty list is a case to handle, not a default. If a function can legitimately return zero items, the interface must distinguish «there are none» from «I do not know»: two different states deserve two different messages.
  • When you find a missing branch, look for who else falls into it. An if handling only the known cases rarely penalises just one. In my case the second one had been there for months, and only surfaced because I happened to be looking that way.
  • Be suspicious of «it works but it does not show». That pairing is almost always a permissions or enumeration problem, almost never business logic.

There is a broader point about moving fast with AI: when you generate a lot of code quickly, missing branches multiply faster than explicit bugs, because an omission breaks nothing and so draws no attention. It is why commit discipline and reviewing what was not handled matter more than the speed it was written at.

FAQ

Why can a display bug survive for months?

Because it generates no errors, is invisible to developers (who run with full permissions), and whoever hits it reads it as their own configuration failure rather than a fault. All three channels through which a normal bug gets reported are missing.

What does «test with the least-privileged account» mean?

It means running acceptance checks with the lowest role that must be able to perform that action, not with the admin account you develop with. It is the only way to walk through the code branches that filter by permission.

How do you distinguish «there are no items» from «I cannot read them»?

By treating them as two different states in the backend and making them distinguishable in the interface. An empty list returned successfully and an empty list because the filter could not classify the case must produce different messages for the reader.

Is this typical of multi-tenant systems?

It is more frequent there, because «which things does this customer see» is exactly where missing branches nest. But it happens anywhere there are roles and permissions: all it takes is an if written around the cases known at the time.


If you have a system where «it works but it does not show» happens more than once, the problem is usually not the individual bug but how permissions and enumeration are organised. Let's talk — it is the kind of review I run often as a Fractional CTO.

Behind the scenesTech LeadershipAI

Scritto da Giulio Garofalo