Exception Handling Isn’t Syntax, It’s Architecture
I was scrolling through LinkedIn the other day — as one does, with a mix of professional curiosity and masochism — when I came across a brightly polished post about “Throwing Exceptions the Right Way in C#.” You’ve probably seen it, or one just like it. Clean diagrams. Green checkmarks. Red Xs. Bite‑sized rules presented as wisdom.
Nothing in it was wrong.
And that, paradoxically, is exactly the problem.
This article was born out of that moment of unease: the feeling that we are increasingly mistaking syntactic hygiene for architectural maturity, and mistaking LinkedIn‑optimized advice for lived engineering experience. Exception handling is a perfect example of this pathology.
Let’s talk about it properly.
The LinkedIn Version of Exception Handling
The now‑familiar checklist goes something like this:
Use specific exception types
Don’t throw
ExceptionNever use exceptions for control flow
Always use
throw;instead ofthrow ex;
Individually, these statements are defensible. Collectively, they create the illusion that exception handling is a local, mechanical concern — a matter of choosing the right keyword and calling it a day.
Real systems don’t fail locally.
They fail systemically.
And the moment your system grows beyond a single method, these rules stop being sufficient and start becoming actively misleading.
What throw; Really Teaches (and What It Doesn’t)
Yes, rethrowing with throw; preserves the original stack trace. Losing it is unforgivable in production debugging. On that, there is no disagreement.
But here’s the uncomfortable truth: a pristine stack trace attached to a meaningless exception is still useless.
If your logs say:
InvalidOperationException: Order state is invalid
Then congratulations — you have preserved perfectly the record of having learned nothing.
Which order? Which state? What transition? What input? What user? What correlation ID?
Stack traces tell you where something exploded.
Context tells you why.
LinkedIn posts obsess over the former because the latter requires design.
The Cardinal Sin Isn’t “throw new Exception”
You’ll often see blanket proclamations like “Never throw Exception.” They sound authoritative. They’re also wrong in any absolute sense.
The real question is not what you throw.
It’s where you throw it.
At system boundaries — between your application and:
A third‑party API
A database driver
A legacy system
A message broker
—you often have no meaningful way to preserve the original exception semantics. Wrapping a low‑level failure into a higher‑level, application‑meaningful exception is not laziness; it is ownership.
The problem isn’t generic exceptions.
The problem is generic thinking.
Exception Ownership: The Topic Everyone Avoids
Here is the part LinkedIn advice never touches, because it doesn’t fit into a carousel:
Every exception must have an owner.
Domain exceptions belong to the domain
Infrastructure exceptions belong to infrastructure
Application services translate, never leak
Presentation layers do not decide business outcomes
If an exception crosses more than one architectural boundary unchanged, something is already wrong.
Exception handling is not about catching errors.
It is about containing failure.
“Never Use Exceptions for Control Flow” (Except When You Should)
This phrase is repeated so often it has become a reflex. And like most reflexes, it lacks judgment.
Exceptions should not represent expected, frequent states — agreed.
But they are often the cleanest expression of violated invariants:
A payment captured twice
A state machine receiving an illegal transition
A security boundary being crossed incorrectly
Encoding these as return values frequently leads to worse code, not better — because now the burden of correctness is silently pushed onto every caller.
Exceptions exist to say:
“This path must not continue.”
Using them responsibly is not immaturity. It’s honesty.
What Mature Exception Handling Actually Looks Like
In real systems, good exception handling has very little to do with the throw keyword and everything to do with discipline:
Exceptions are rare, intentional, and documented
Messages are written for humans, not compilers
Context is captured once, close to the source
Exceptions are translated at boundaries
Logs are structured and correlated
Callers either handle an exception or deliberately let it crash
None of this fits in a “Pro Tips” box.
The Social Media Distortion Field
Why does shallow advice dominate?
Because LinkedIn rewards:
Certainty over nuance
Rules over reasoning
Syntax over systems
It is safer to say “Always do X” than to explain when X is insufficient.
It is easier to teach mechanics than judgment.
But judgment is what keeps production systems alive.
Closing Thought
If exception handling were merely about choosing the right exception type, debugging modern software would be trivial.
It isn’t.
Failures are narratives. They tell a story about what your system believed, what assumptions broke, and how well you anticipated reality pushing back.
Clean code doesn’t come from memorizing rules.
It comes from designing for failure — and taking responsibility when it happens.
Everything else is just syntax dressed up as wisdom.

Comments
Post a Comment