// When it breaks, triage before you rebuild · lesson 03

Surface fix versus semantic fix

There are two ways to make a bug go away, and only one of them is fixing it. The surface fix makes the symptom disappear. The semantic fix removes the cause. If you cannot tell which one you just did, you will be back here soon, patching the same failure wearing a different mask.

Here is the difference in practice. Say a value shows up as undefined and crashes a page. The surface fix adds a check: if it is undefined, use a default, move on, symptom gone. The semantic fix asks why the value was undefined in the first place, and discovers the data was never being loaded, or was loaded under the wrong key, or the API changed shape. The surface fix hides the missing data behind a default. The semantic fix restores the data. Both make the crash stop. Only one is correct, and the other is now lying to you with a plausible-looking default.

How do you know which fix you're making?

Ask one question: what made this bug possible, and is that thing still true after my change? If the underlying condition is still there and you have only stopped it from showing, that is a surface fix, and it is often worse than the bug because now the failure is silent. A crash at least tells you something is wrong. A default value quietly papering over missing data tells you nothing while it corrupts everything downstream that trusts that value.

AI makes this trap especially easy to fall into, because models are very good at producing surface fixes. Ask an AI why something is broken and it will happily generate a try-catch, a null check, a fallback, anything that makes the error stop. That is the model optimizing for "the symptom is gone," which looks like success. It takes a human asking "but why did it happen" to push from the surface to the cause, because the model will not push there on its own unless you make it.

The rule I hold is that a fix is not done when the symptom disappears. It is done when I can name the cause and confirm my change removed it. If I patched the symptom and cannot explain the cause, I did not fix the bug, I hid it, and hidden bugs compound.

The takeaway: A surface fix hides the symptom; a semantic fix removes the cause. Ask what made the bug possible and whether it's still true after your change, because a silent patch is often worse than the original crash.