The Two Fundamental, No Frills, Square One Rules of Exception Handling

When I was a coding newbie I thought applications should never crash. I wrote code that caught and ignored errors because I didn’t know how else to handle them. I didn’t want the user to see an error page, and figured a running application was always better than an error page. Oh, how wrong I was. On one application alone (not written by me) I wasted 50+ hours over the course of a few months because of exceptions that were caught and not properly handled. Don’t let this happen to you.

I’ve found this mindset to be so common among new developers that I’ve distilled the basics down to two fundamental rules a new developer should follow to the letter. I’m exhausted with cracking open code and seeing a Try/Catch block with no action after the catch. Whether you’re using a language with actual exceptions is beside the point – what matters is that you read through these few simple paragraphs and never, ever obfuscate your application errors.

Picture this (in C#):

Try
{

‘ Application code here
}
Catch
{

‘ Do nothing
}

What happens when an exception is thrown from the application code? Nothing…and that’s a problem.

Let’s say the application is attempting to insert a value into the database. Instead of a crash and some type of error message (even the default message would be helpful), the program continues to execute. At some point in the future, perhaps seconds, minutes, or weeks, another piece of code comes along looking for that database value and doesn’t find it. The result is a crash. Well, hopefully a crash. An even more likely case is that it will continue to execute and write 1s and 0s over the only remaining copy of your grandmother’s priceless rhubarb pie recipe. Or worse, the only remaining copy of the financial statements for your grandmother’s rhubarb pie factory. Yes sir, dirty data is eeee-vil.

With that in mind, let’s take a look at these two simple rules:

Rule #1: If you can’t add helpful information to an error message, don’t catch the exception.

If you are simply going to catch and re-throw an exception, you are better off removing your Try/Catch block and letting the runtime throw the exception for you. In other words, if you don’t know why you’re adding a try/catch block, don’t add it.

Rule #2: If you catch an exception, log it.

I’ve seen this rule broken in at least 10 applications in the past 6 months. Use log4j, log4net, Microsoft’s Logging Application Block, a text file, morse code, or carrier pigeon…just log the damn thing. Never catch an exception and do nothing unless you are writing a tool used to log exceptions.

Logging exceptions is not just a good idea, it allows you to know about errors before your customer does and is an invaluable tool for maintaining a healthy application.

If you have other exception management suggestions feel free to post them to the comments.

[tags]asp.net, .net, exceptions, error handling[/tags]

Start Small, Get Big
Growth Secrets for Self-Funded Startups. It'll Change Your Life.
What you get for signing up:
  • A 170-page ebook collecting my best startup articles from the past 5 years
  • Previously unpublished startup-related screencasts
  • Exclusive revenue-growing techniques I don't publish on this blog
"The ideas and information Rob provides should be required reading for anyone that wants to create a successful business on the web." ~ Jeff Lewis
Startups for the Rest of Us...
If you're trying to grow your startup you've come to the right place. I'm a serial web entrepreneur here to share what I've learned in my 11 years as a self-funded startup founder. Luckily several thousand people have decided to stick around and join the conversation.

For more on why you should read this blog, go here.

11 comments ↓

#1 Oli on 08.27.07 at 8:00 pm

…and if you’re going to re-throw, please create a new Exception subclass instance, initialized with the caught one! Example: int zero = 0; try { int result = 1 / zero; } catch ( DivideByZeroException dbze ) { // TODO: maybe log dbze’s details here throw new ApplicationException ( “The computer can’t do complex math properly!”, dbze ); } …this allows whoever catches ApplicationException to also see the previous stack trace, otherwise all you know is that an ApplicationException was thrown as a result of a DivideByZeroException caused by some unknown code within the “try”. (imagine, for an instant, that there were several statements possibly causing a DBZE) – Oli

#2 http:// on 08.27.07 at 9:55 pm

If you are working with ASP.NET you can use the HttpApplication class and implement the Application_Error event handler to catch exceptions at the global level in your global.asax.cs code behind.

#3 http:// on 08.27.07 at 9:56 pm

There are a few instances when you might want an empty catch. For instance, if you are attempting to recover from an otherwise exceptional condition attempting to make sure that resources are closed gracefully – perhaps as part of a ‘finally’ block. If this is intentional, it is normally a good idea to comment to that fact.

#4 Tim Rowe on 08.28.07 at 12:12 am

I don’t always agree with Oli. In cases where you are doing nothing with an exception but logging it, and aren’t sure how to handle it, wrapping it in another exception isn’t necessarily a good idea. Especially if you have some exceptions in your code where you know how to handle at a higher level, but this one you don’t. try { foo(); } catch (NullPointerException e) { log.warning(“Aieeee”); throw e; } Is perfectly fine if you’re not actually fixing the problem. Throwing it as MyException(e); though might cause more headaches than you’ve solved. A better option is something like MyException e = new MyException(e); e.setErrorCode(ERR_OH_BOTHER); Rather than subclassing every exception type known to man. That would also allow you to have a lookup table of your errors to error messages, and nicely use I18n.

#5 Brian Donahue on 08.28.07 at 3:07 am

A big one – you should virtually never be catching the generic, base Exception, unless you are definitely just logging and re-throwing or re-casting. If you are handling, ONLY catch the exception you expect to handle, let all others bubble up!

#6 Rob Walling on 08.28.07 at 3:08 pm

Tone – a good reminder. I wrote an article about this a few years ago, it’s available here: http://www.dotnetbips.com/articles/displayarticledetails.aspx?articleid=215. RevMike – You don’t need a catch to have a finally block; this is a common misconception. Oli & Tim – You’ve discovered a source of some heated debates I’ve witnessed: response codes vs. custom exceptions. I tend to use response codes, but there are good arguments on both sides of this issue.

#7 Oli on 08.28.07 at 3:43 pm

Tim, what does you stack trace look like when your NullPointerException is finally caught? In my tests with .NET 1.1, I found that a “rethrow” (either as “throw;” or “throw e;”, as in your example) will obfuscate the origin of the original exception and thus the only way to find out which line actually caused a NPE (supposing there were several statements in your “try” block) is to throw a new exception that embeds the caught one. Anyway, I think we’re diverging from the point, which was, uhhh… ah ha: “If you can’t add helpful information to an error message, don’t catch the exception.” Cheers, – Oli

#8 Erik Lane on 08.29.07 at 3:45 am

It’s called an exception for a reason. When it occurs it’s an exceptional situation or circumstance. My thoughts have always been this – don’t touch an exception unless you are going to do something with it. Otherwise, it will eventually find you and make you do something with it.

#9 http:// on 08.29.07 at 12:42 pm

Hi, I get into this issue today. I think you read my mind. In my case, instead of catching the exception and ignoring it, the developer has returned the “null” value. I lost 5 hours to figure out this ! Please, my friends, never do this !!!

#10 Micahel Chermside on 08.30.07 at 6:03 pm

Here are the rules that I use. It differs from your statement only in some nuances. Only catch an exception if there is something that your code can do about it. … So, it’s perfectly OK to catch the FileWasBusyException and try opening over again (but limit your NUM_TRIES to 3 or 4). It’s perfectly OK to catch the SpreadsheetRecalcuationException thrown by speedyRecalc() and invoke slowButReliableRecalc() instead. It’s also perfectly OK to catch an exception and return null _IF_ your function header reads like this: /** * This function calculates the price of rubarb. * It returns a RubarbPrice object if the * calculation was successful, and returns * null if the calculation failed. */ Of course, if your function definition does NOT read like that, then catching exceptions and returning null is NOT acceptable. As a special corollary, it is permissible to catch an exception, do some logging, then re-throw the exception, or catch an exception then throw a new exception that has at least as much information. (At least as much information almost certainly means it includes a pointer to the original exception.) An obvious extension of this is that you must catch the most precise exception type that you can handle. Catching FileWasBusyException and re-trying is fine… catching Exception and re-trying is inappropriate… because if what you caught turns out to be a OutOfMemoryException or something like that, then you aren’t actually doing anything about the problem. _All_ real programs have a place near the bottom of the callstack that _does_ catch the most generic Exception possible and handles it. If your program doesn’t do this, then I say yours is just a “toy” program. This handling point may simply log the exception, or it may generate a memdump file and schedule it to be transmitted to the emergency support team… but it handles it SOMEHOW. Many interesting applications have a super-exception-handler at the bottom of a few different layers. When YOU are writing code, you should TRUST that the super-error-handler will be there… that SOMEONE below you in the call stack will take care of things. So if you can’t fix it, you MUST NOT catch the exception.

#11 MJ on 09.24.09 at 12:52 am

@Oli, never log and exception and then re-throw it. That is an exception handling anti-pattern. The code that handles the exception should log it.