AI Translated Document
- This document was translated using an AI translation tool.
- Due to the nature of AI translation, some sentences or terms may be interpreted differently from the original intent.
- There may be mistranslations or inaccuracies, so please refer to the original text or consider additional review if accuracy is critical.
- Your suggestion for a better translation would be highly appreciated.
Original Document in Korean
Please, Reduce catch¶
HJ, Ph.D. / Software Architect (js.seth.h@gmail.com) Draft: July 2021 / Revised: October 2025
[Interpretive Note] This article was written to highlight that increasing exception handling can actually create a structure that hides the root cause of errors.
Executive Summary¶
- There are too many misguided guidelines or recommendations for try-catch. Here are some examples:
- Use try-catch only within a reasonable range where predictable exceptions may occur.
- Wrap the minimal code block with try-catch to clearly identify exception situations.
- Catch only specific exceptions.
- Distinguish between recoverable and unrecoverable exceptions.
- For recoverable exceptions, handle them so the program continues normally; for unrecoverable ones, log and terminate if necessary.
- Define exceptions (or return values) with clear and specific names.
- Convert to meaningful exceptions by layer and pass them to upper layers.
- Reality is very different.
- If it's perfectly predictable, it's not an exception.
- If you don't install a crash barrier at external service boundaries, the whole system is likely to stop. First, cover everything. Details come later.
- Catch all or catch nothing. Catching specific errors doesn't help much for overall robustness.
- If a program can recover as a feature, it's not an exception. If you understand throw-catch, recoverability is not the point.
- In reality, recoverable exceptions don't exist—especially when external systems (DB, Web API) are involved. And never, ever terminate.
- Even if local info is specific, you often can't reproduce the problem. You need all surrounding info. Don't waste energy on error messages.
- Passing up means becoming more abstract and losing specificity. Does this help with understanding or resolution?
- First, understand how reckless throw really is.
- Focus on understanding the situation and responding appropriately, rather than trying to overcome exceptions.
If It's Predictable, It's Not an Exception¶
Of course, some exceptions are predictable. But you can't predict all exceptions. Just this fact alone means you must write defensive strategies for the truly unpredictable—literal exceptions.
There is no such thing as a "reasonable range" for exception handling—there is only the final barrier. Instead of worrying about reasonable use, focus first on global exception handlers and service boundaries.
The Final Barrier¶
Where the system interfaces with the outside, especially for external input, you should use try-catch as broadly as possible.
For example, for network receive, wrap everything after receive in try-catch, and discard everything until reconnection or resynchronization to keep the service alive. try-catch should be broad, not narrow; coverage is more important than detail.
If France's Maginot Line had extended to Belgium, history might have changed.
If you don't want to get called at 3 a.m., think about this seriously.
Catch All or Nothing¶
"A chain is only as strong as its weakest link"
This is a proverb often mentioned in security.
In security, if a single path is breached, the whole is breached.
Likewise, for software, if a single path is left unhandled, you might get called at 3 a.m.
At the final barrier, you must catch all exceptions.
What matters here is gracefully refusing service, not just doing something.
So the most important throw-catch—the final barrier—must always be catch-all.
Catching specific errors is only possible when it doesn't really matter. Such cases do exist, but most features have clear reasons and purposes, so there is no substitute. So, most exceptions mean overall feature failure, and it's best to handle them at the final barrier.
As a result, most routines have no reason to catch.
Graceful service refusal means: the service doesn't die, the user isn't frustrated, but ultimately the requested task isn't done.
The throw-catch Mechanism Doesn't Consider Recoverability¶
When an exception occurs, throw immediately stops the current function and unwinds the call stack until a catch block is found. All local state, variables, and context info in the stack are lost.
So, from the point of exception to the catch, all functions in between are only partially executed, and you can't know what resources were open or what state things were in. You don't know what succeeded. Especially with external libraries or systems (DB, file, network), after throw, you can't know the state. In this structure, "recovery" is basically impossible. The context and data needed for recovery are gone.
In the end, the only possible "recovery" after an exception is to recalculate the correct final result and overwrite everything inside and out. More deeply, you can't recover the computation itself, only reset the result data to a known point. If you understand the essence of throw-catch, you see that recoverability is not even a topic.
For a program, throw-catch is...
For a program, throw is like a "dungeon escape item." You give up everything and just save your life.
And catch is the dungeon entrance. Multiple catches in the call stack are like nested dungeons.
If you use an escape item but end up in another dungeon, what's the point?
So, please, use it sparingly.
In Reality, Recoverable Exceptions Don't Exist¶
Think about the external system almost every project uses: the database.
Suppose you have an increment operation, update tbl_X set a = a+1 where id = 99, and some function calls it, sometimes through a branch. If an error occurs and the final barrier's throw-catch is triggered—
Did the DB increment or not? What if AutoCommit is on?
The error could have been a network disconnect, or maybe the DB committed and sent a reply to the OS, but the connection broke after. We often can't know what succeeded.
But whether the operation failed isn't as important as you think. What matters is the final data. So, trying to recover immediately in code is less important than you think. The most important thing is that the final result is correct.
First, correct the result as soon as possible (e.g., within 24 hours)—that's all the business wants.
If You Really Have a Second, Immediate Alternative...¶
That means your development/operating costs are doubled.
If your schedule or staff isn't doubled, it means 80-hour workweeks.
Never Die¶
Never terminate. Never kill the process.
Do you really want to go to work at 3 a.m.?
How to Reproduce a Problem¶
To perfectly reproduce a problem, conceptually you need two things:
- The same environment—environment variables, DB info, memory traces, what other threads were doing, etc.
- The same input
Of course, for most real problems, a similar environment and the same input is enough. But with just the exception text, you can't do much.
Instead of spending time on detailed exception messages, what you need is a proper logging system. You don't need 5-minute DB snapshots and full input logs for 5–10 minute replay, but—
If you can set up a similar environment and provide the same input, that's enough.
Preserve Specificity¶
What can you do at the upper layer? At best, display "Order failed."
In reality, you might get Divide By Zero from money calculations, or Out of Index from input errors or stock changes. But you don't have time to specify all these messages, and if you understand the situation that well, you should block it before it gets to the logic.
To handle exceptions properly, developers need concrete info. But what can you do with just "Order failed"? What you really need is concrete info. It's best to have the full call stack, exact error time, and enough input to reproduce the error.
You need to get this info somehow—it doesn't have to be in the exception message.
Recommended method
My favorite way is to save a serial number and all external input for every request at the final barrier,
save the full call stack on exception,
and show the user "Order failed. Error number 00000. Please contact the administrator."
Conclusion¶
throw-catch is honestly a very reckless feature. Most modern languages descend from C/C++, but C got throw in 1989 (C++), and C still doesn't have it.
You might think it's a natural language feature, but historically and practically, it's not. In programming language theory, throw-catch is no different from a dynamic goto (a goto whose target is decided at runtime).
It's powerful, and when used properly, it's very beneficial, so you must understand its nature and use it strategically.
- Don't overuse exceptions; always set up a final barrier for the truly unpredictable.
- Don't try to solve problems with exceptions—use them as an emergency escape.
- Don't rely only on exceptions for understanding—prepare other means too.
- For business, put expected and recoverable cases in the normal routine, and use exceptions only for cases the business doesn't anticipate.
Pretty exception messages, meticulous try-catch, and catching as many exceptions as possible are not the important parts. Those things are not more important than not getting called at 3 a.m. or not getting a claim with no clues. Check what really needs to be done, and focus on that.
See Also¶
- Proof of the Possibility of a One Man Framework - What is possible with solid exception handling
- Distrustful Coding vs Trustful Coding - Macro development strategies including exceptions
- Architecture Is a Structural Solution - This document introduces a structural solution for exceptions
- Static Typed Languages (TS) vs Dynamic Typed Languages (JS): Different Approaches - How type systems affect throw-catch perspectives
Author¶
HJ, Ph.D. / Software Architect
(js.seth.h@gmail.com)
https://js-seth-h.github.io/website/Biography/
Over 20 years in software development, focusing on design reasoning and system structure - as foundations for long-term productivity and structural clarity.
Researched semantic web and meta-browser architecture in graduate studies,
with an emphasis on structural separation between data and presentation.
Ph.D. in Software, Korea University
M.S. in Computer Science Education, Korea University
B.S. in Computer Science Education, Korea University
)