March 26 2025
Error Handling Without Empty Try/Catch Theater
How to handle errors in a way that helps the people who operate, debug, and evolve the system instead of hiding failure behind random fallbacks.
Andrews Ribeiro
Founder & Engineer
4 min Intermediate Systems
The problem
A lot of code “handles errors” like this:
try {
process()
} catch (error) {
console.log(error)
}
That looks safe.
It is not.
In practice, that kind of block often:
- swallows context
- hides the real failure
- lets the flow continue in a broken state
- makes debugging harder later
In other words, the error did not disappear. It just became worse to understand.
Mental model
Think about it like this:
handling an error is not silencing an exception; it is giving the failure the right destination
That destination changes depending on the case:
- log it
- propagate it
- translate it
- abort the flow
- try again
The important part is making that decision with criteria. Not by reflex.
Breaking it down
First understand what kind of error this is
Some questions help:
- is this a business error or a technical error?
- is it an expected error or an anomaly?
- is it temporary or permanent?
- can the user act on it?
Without that separation, every error becomes one amorphous mass.
Then decide what to do with it
The most common options are:
- log it with context
- return a clear response
- stop the flow
- propagate it to an upper layer
- apply a retry with criteria
The mistake here is using the same answer for everything.
Preserve context
If you catch an error and replace it with something else without preserving context, debugging gets expensive.
Replacing:
payment_provider_timeout request_id=...
with:
something went wrong
is a very efficient way to hate your own future 3 AM incident.
Do not turn catch into a hiding place
Using catch only because “what if it fails” is a weak pattern.
If the current layer does not know how to resolve the failure, many times it should:
- add context
- and pass it along
Not pretend it solved it.
Simple example
Imagine one call to a payment gateway.
Weak handling:
- catch any error
- log one generic string
- return
false
Now the caller does not know:
- was it a timeout?
- was the card declined?
- were the credentials invalid?
- is a retry useful?
Better handling:
- distinguish business error from technical error
- log useful context
- return something to the upper layer that allows the right reaction
Example:
- declined card: business response, no retry
- provider timeout: technical error, maybe retry or temporary-unavailable message
- invalid credential: configuration incident, needs operational alert
The code is still simple. But the system becomes much easier to operate.
Common mistakes
- using a generic
catchand continuing the flow as if nothing happened - losing the original stack trace or error while translating the exception
- retrying an error that will never improve on its own
- showing too much internal detail to the end user
- mixing expected business errors with serious technical failure
How a senior thinks
More experienced engineers think about the whole path of the failure.
The reasoning often sounds like this:
“If this goes wrong, who needs to know? What can actually be done in this layer? What context do I need to preserve so the next person or the next layer can understand what happened?”
That mindset avoids two bad extremes:
- exploding everything without criteria
- swallowing everything without criteria
What the interviewer wants to see
In interviews, this topic measures technical judgment.
The evaluator wants to see whether you:
- distinguish types of error
- preserve context
- know when to propagate
- do not use
try/catchas cosmetic robustness
A strong answer often sounds like this:
“I would try to separate expected business errors from technical failure. The layer that catches the error needs either to actually resolve it or to add context and propagate it. What I would avoid is a generic catch that hides the cause and leaves the rest of the system unable to react correctly.”
Good error handling does not make the problem disappear. It makes the problem more governable.
An empty catch is the fastest way to trade a clear error for a bad investigation.
Quick summary
What to keep in your head
- Good error handling makes clear what happened, who needs to know, and what the system should do next.
- Swallowing an error with a generic catch usually trades a visible failure for a confusing one.
- Not every error deserves a retry, and not every error deserves a detailed user message.
- Thinking well about errors improves debugging, operations, and predictability at the same time.
Practice checklist
Use this when you answer
- Can I explain the difference between logging, propagating, translating, and hiding an error?
- Do I know when a catch block is helping and when it is masking the problem?
- Can I design an error path that preserves useful context for investigation?
- Can I answer in an interview how I would handle an error without falling into empty try/catch?
You finished this article
Share this page
Copy the link manually from the field below.