70

I typically agree with most code analysis warnings, and I try to adhere to them. However, I'm having a harder time with this one:

CA1031: Do not catch general exception types

I understand the rationale for this rule. But, in practice, if I want to take the same action regardless of the exception thrown, why would I handle each one specifically? Furthermore, if I handle specific exceptions, what if the code I'm calling changes to throw a new exception in the future? Now I have to change my code to handle that new exception. Whereas if I simply caught Exception my code doesn't have to change.

For example, if Foo calls Bar, and Foo needs to stop processing regardless of the type of exception thrown by Bar, is there any advantage in being specific about the type of exception I'm catching?

Maybe a better example:

public void Foo()
{
    // Some logic here.
    LogUtility.Log("some message");
}

public static void Log()
{
    try
    {
        // Actual logging here.
    }
    catch (Exception ex)
    {
        // Eat it. Logging failures shouldn't stop us from processing.
    }
}

If you don't catch a general exception here, then you have to catch every type of exception possible. Patrick has a good point that OutOfMemoryException shouldn't be dealt with this way. So what if I want to ignore every exception but OutOfMemoryException?

7
  • 14
    What about OutOfMemoryException? Same handling code as everything else?
    – Patrick
    Commented Sep 9, 2012 at 15:23
  • @Patrick Good point. I added a new example in my question to cover your question.
    – Bob Horn
    Commented Sep 9, 2012 at 16:23
  • 1
    Catching general exceptions is about as bad as making general statements about what you everyone should do. There is generally no one-size-fits-all approach to everything.
    – user37718
    Commented Sep 13, 2012 at 17:40
  • 5
    @Patrick that would be OutOfMemoryError, which is separate from the Exception inheritance tree for that very reason
    – Darkhogg
    Commented Jan 17, 2015 at 17:02
  • 1
    @Patrick you take into account in every code path there could be OutOfMemory exception? That must be very exhausting code to read 😁
    – Dirk Boer
    Commented Nov 20, 2022 at 13:48

12 Answers 12

40

These rules are generally a good idea and thus should be followed.

But remember these are generic rules. They don't cover all situations. They cover the most common situations. If you have a specific situation and you can make the argument that your technique is better (and you should be able to write a comment in the code to articulate your argument for doing so) then do so (and then get it peer reviewed).

On the counter side of the argument.

I don't see your example above as a good situation for doing so. If the logging system is failing (presumably logging some other exception) then I probably do not want the application to continue. Exit and print the exception to the output so the user can see what happened.

5
  • 2
    Concur. At the very least, now that regular logging is offline make some kind of provision that'll give some kind of debugging output, to STDERR if nothing else. Commented Sep 10, 2012 at 4:20
  • 11
    I upvoted both of you, but I think that you are thinking like developers, not users. A user generally does not care whether logging is happening, so long as the application is useable.
    – Mawg
    Commented Dec 10, 2014 at 9:19
  • 1
    Interesting, as log4net explicitly doesn't want to stop the app just because logging fails. And i think it depends on what you're logging; security audits, sure, kill the process. But debug logs? Not that important.
    – Andy
    Commented Aug 26, 2015 at 18:02
  • @Mawg in this instance I would say the consumer of the logs may be a developer but they are in the role of a maintenence user. Failure to log errors can obscure the source and nature of other errors. I think the mantra of don't handle errors you don't understand still applies.
    – Sprague
    Commented Aug 5, 2016 at 13:54
  • 3
    Why don't you understand them? And should you not strive to do so?
    – Mawg
    Commented Aug 6, 2016 at 8:51
35

Yes, catching general exceptions is a bad thing. An exception usually means that the program cannot do what you asked it to do.

There are a few types of exceptions that you could handle:

  • Fatal exceptions: out of memory, stack overflow, etc. Some supernatural force just messed up your universe and the process is already dying. You cannot make the situation better so just give up
  • Exception thrown because bugs in the code that you are using: Don't try to handle them but rather fix the source of the problem. Don't use exceptions for flow control
  • Exceptional situations: Only handle exception in these cases. Here we can include: network cable unplugged, internet connection stopped working, missing permissions, etc.

Oh, and as a general rule: if you don't know what to do with an exception if you catch it, it is better to just fail fast (pass the exception to caller and let it handle it)

14
  • 4
    Why not fix the bug in the logging code instead? Commented Sep 9, 2012 at 21:30
  • 5
    Victor, it's probably not a bug. If the disk the log lives on runs out of space, is that a bug in the logging code? Commented Sep 10, 2012 at 0:05
  • 4
    @Carson63000 - well, yes. The logs aren't being written, therefore: bug. Implement fixed size rotating logs.
    – detly
    Commented Sep 10, 2012 at 0:36
  • 6
    This is the best answer imo, but it is missing one crucial aspect: security. There are some exceptions that occur as a result of the bad guys trying to f-up your program. If an exception gets thrown that you are unable to handle, then you cannot necessarily trust that code anymore. Nobody likes to hear that they wrote the code that let the bad guys in.
    – riwalk
    Commented Sep 10, 2012 at 2:04
  • 3
    @detly: The disk can still run out of space, even if you implement fixed size rotating logs. Is it still a bug in the logging code? Commented Aug 15, 2013 at 17:50
17

The topmost outer loop should have one of these to print all it can, and then die a horrific, violent and NOISY death (as this shouldn't happen and someone needs to hear).

Otherwise you should generally be very careful as you most likely have not anticipated everything that could happen at this location, and hence will most likely not treat it correctly. Be as specific as possible so you only catch those you know will happen, and let those not seen before bubble up to the above mentioned noisy death.

10
  • 2
    I agree with this in theory. But what about my logging example above? What if you simple want to ignore logging exceptions and continue? Should you need to catch every exception that could be thrown and handle each of those while letting the more serious exception bubble-up?
    – Bob Horn
    Commented Sep 9, 2012 at 16:45
  • 7
    @BobHorn: Two ways of looking at that. Yes, you can say that logging isn't particularly important and if it fails then it shouldn't bring your app to a halt. And that's a fair enough point. But, what if your application fails to log for five months and you had no idea? I've seen this happen. And then we needed the logs. Disaster. I would suggest doing everything you can think of to stop logging failing is better than ignoring it when it does. (But you're not going to get much of a consensus on that.)
    – pdr
    Commented Sep 9, 2012 at 17:12
  • 1
    @pdr In my logging example, I would typically send an email alert. Or, we have systems in place to monitor logs, and if a log isn't being actively populated, our support team would get an alert. So we'd become aware of the logging issue in other ways.
    – Bob Horn
    Commented Sep 9, 2012 at 17:23
  • @BobHorn your logging example is rather contrived - most logging frameworks I know of, go to great length to not throw any exceptions and would not be invoked like that (as it would make any "log statement happened at line X in file Y" useless)
    – user1249
    Commented Sep 9, 2012 at 17:44
  • @pdr I've raised the question at the logback list (Java) on how to make the logging framework halt the application if logging configuration fails, simply because it is SO important we have the logs, and any silent failure is unacceptable. A good solution is still pending.
    – user1249
    Commented Sep 9, 2012 at 17:46
12

It's not that it's bad, it's just that specific catches are better. When you're specific, it means that you actually understand, more concretely, what your application is doing, and have more control over it. In general, if you come upon a situation where you just catch an Exception, log it and continue, there's probably some bad things that are going on anyway. If you're specifically catching the exceptions that you know a code block or method can throw, then there's a higher likelihood you can actually recover instead of just logging and hoping for the best.

1
  • There is a fairly common situation with a catch block that wraps the exception in additional context information. You really do understand concretely that you need to wrap all exceptions in this manner, and catching only some of them leaves open the possibility that in the future there will be new exceptions that are missed. You should NEVER just log and continue.
    – AgilePro
    Commented Apr 15 at 16:58
6

The two possibilities are not mutually exclusive.

In an ideal situation, you would catch all possible types of exception your method could generate, handle them on a per-exception basis, and in the end add a general catch clause to catch any future or unknown exceptions. This way you get the best of both worlds.

try
{
    this.Foo();
}
catch (BarException ex)
{
    Console.WriteLine("Foo has barred!");
}
catch (BazException ex)
{
    Console.WriteLine("Foo has bazzed!");
}
catch (Exception ex)
{
    Console.WriteLine("Unknown exception on Foo!");
    throw;
}

Keep in mind that in order to catch the more specific exceptions, you must put them first.

Edit: For reasons stated in the comments, added a rethrow in the last catch.

7
  • 2
    Wait. Why would you ever want to log an unknown exception to console and carry on? If it's an exception that you didn't even know could be thrown by the code, you're probably talking about a system failure. Carrying on in this scenario is probably a really bad idea.
    – pdr
    Commented Sep 9, 2012 at 15:43
  • 1
    @pdr Surely you realize it's a contrived example. The point was to demostrate catching of both specific and general exceptions, not how to handle them.
    – Rotem
    Commented Sep 9, 2012 at 15:48
  • 1
    @Rotem I think you have a good answer here. But pdr has a point. The code, as is, makes it look like catching and continuing is fine. Some beginner, seeing this example, might think that's a good approach.
    – Bob Horn
    Commented Sep 9, 2012 at 16:14
  • Contrived or not, it makes your answer wrong. As soon as you start catching exceptions like Out Of Memory and Disk Full and just swallowing them, you're proving why catching general exceptions is in fact bad.
    – pdr
    Commented Sep 9, 2012 at 16:16
  • 1
    If you catch a general exception only to log it, then you should rethrow it after logging. Commented Sep 9, 2012 at 16:20
6

I have been pondering the same recently, and my tentative conclusion is that the mere question arises because the .NET Exception hierarchy is severely messed up.

Take, for example, the lowly ArgumentNullException which might be a reasonable candidate for an exception you don't want to catch, because it tends to indicate a bug in the code rather than a legitimate runtime error. Ah yes. So does NullReferenceException, except that NullReferenceException does derive from SystemException directly, so there's no bucket you can place all "logical errors" into to catch (or not catch).

Then there is the IMNSHO major botch of having SEHException derive (via ExternalException) SystemException and thus make it a "normal" SystemException When you get an SEHException, you want to write a dump and terminate as fast as you can -- and starting with .NET 4 at least some SEH exceptions are considered Corrupted State Exceptions that will not be caught. A good thing, and a fact that makes the CA1031 rule even more useless, because now your lazy catch (Exception) will not catch these worst types anyway.

Then, it seems that the other Framework stuff rather inconsistently derives either Exception directly or via SystemException, making any attempt at grouping catch-clauses by something like severity moot.

There's a piece by Mr. Lippert of C# fame, called Vexing Exception, where he lays out some useful categorization of exceptions: You could argue you only want to catch "exogenous" ones, except ... C# the language and the design of the .NET framework exceptions make it impossible to "catch only exogenous ones" in any succinct manner. (and, e.g, an OutOfMemoryException may very well be a totally normal recoverable error for an API that has to allocate buffers that are somehow large)

Bottom line for me is, that the way C# catch blocks work and the way the Framework exception hierarchy is designed, rule CA1031 is beyond totally useless. It pretends to help with the root issue of "do not swallow exceptions" but swallowing exceptions has zero to do with what you catch, but with what you then do:

There are at least 4 ways to legitimately handle a caught Exception, and CA1031 only seems to superficially handle one of them (namely the re-throw case).


As a side note, there's a C# 6 feature called Exception Filters that will make CA1031 slightly more valid again since then you will be able to properly, properly, properly filter the exceptions you want to catch, and there's less reason to write an unfiltered catch (Exception).

3
  • 1
    A major problem with OutOfMemoryException is that there's no nice way code can be sure that it "only" indicates the failure of a particular allocation one was prepared to have fail. It's possible that some other more serious exception was thrown, and an OutOfMemoryException occurred during stack unwinding from that other exception. Java may have been late to the party with its "try-with-resources", but it handles exceptions during stack unwinding a bit better than .NET.
    – supercat
    Commented Apr 21, 2015 at 18:05
  • 1
    @supercat - true enough, but that's pretty much true of any other general System exception, when stuff goes bad in any finally block.
    – Martin Ba
    Commented Apr 21, 2015 at 18:13
  • 1
    That's true, but one can (and generally should) guard finally blocks against exceptions that one can realistically expect to occur in such a way that the original and new exceptions both get logged. Unfortunately, doing that will often require memory allocation, which could cause failures of its own.
    – supercat
    Commented Apr 21, 2015 at 18:33
4

Pokemon exception handling (gotta catch em all!) is certainly not always bad. When your exposing a method to a client, especially an end user its often better to catch anything and everything rather than have your application crash and burn.

Generally though they should be avoided where you can. Unless you can take specific action based on the type of the exception its better not to handle it and allow the exception to bubble up rather then swallow the exception or handle it incorrectly.

Have a look at this SO answer for more reading.

7
  • 1
    This situation (when a developer must be a Pokemon Trainer) appears when you are making an entire software yourself: you made the layers, database connections and user's GUI. Your app must recover from situations like connectivity lost, user´s folder deleted, data corrupted, etc. End Users don't like apps that crash and burn. They like apps that can work on a burning exploding crashing computer! Commented Mar 3, 2014 at 16:00
  • I hadn't thought of this until now, but in Pokemon, it's generally assumed that by 'catch them all' you want exactly one of each, and have to handle catching it specifically, which is the opposite of the common use of this phrase among programmers.
    – Magus
    Commented Apr 3, 2014 at 19:45
  • 2
    @Magus: With a method like LoadDocument(), it's essentially impossible to identify all the things that might go wrong, but 99% of exceptions that could be thrown will simply mean "It was not possible to interpret the contents of a file with the given name as a document; deal with it." If someone tries to open something that isn't a valid document file, that shouldn't crash the application and kill any other open documents. Pokemon error handling in such cases is ugly, but I don't know any good alternatives.
    – supercat
    Commented Jul 9, 2014 at 20:53
  • @supercat: I was just making a linguistic point. However, I don't think invalid file contents sound like something that should throw more than one kind of exception.
    – Magus
    Commented Jul 9, 2014 at 22:56
  • 1
    @Magus: It can throw all sorts of exceptions--that's the problem. It's often very difficult to anticipate all the kinds of exceptions that might get thrown as a consequence of invalid data in a file. If one doesn't use PokeMon handling, one risks having an application die because e.g. the file one was loading contained an exceptionally-long string of digits in a place which required a decimal-formatted 32-bit integer, and a numerical overflow occurred in the parsing logic.
    – supercat
    Commented Jul 9, 2014 at 23:02
1

Catching general exception is bad because it leaves your program in an undefined state. You don't know where stuff went wrong so you don't know what your program has actually done or hasn't done.

Where I would allow catching all is when closing a program. As long as you can clean it up alright. Nothing as annoying as a program you close which just throws an error dialog that does nothing but sit there, not going away and preventing your computer from closing down.

In a distributed environment your log method could backfire: catching a general exception could mean your program still holds a lock on the log-file preventing other users from making logs.

1
  • There is a fairly common situation with a catch block that wraps the exception in additional context information. You really do want to wrap all exceptions in this manner, and catching only some of them leaves open the possibility that in the future there will be new exceptions that are missed. This does NOT leave your application in an undefined state.
    – AgilePro
    Commented Apr 15 at 17:00
0

I understand the rationale for this rule. But, in practice, if I want to take the same action regardless of the exception thrown, why would I handle each one specifically?

As others have said, it's really difficult (if not impossible) to imagine some action that you'd want to take regardless of the exception thrown. Just one example are situations where the program's state has been corrupted and any further processing can lead to problems (this is the rationale behind Environment.FailFast).

Furthermore, if I handle specific exceptions, what if the code I'm calling changes to throw a new exception in the future? Now I have to change my code to handle that new exception. Whereas if I simply caught Exception my code doesn't have to change.

For hobby code it's just fine to catch Exception, but for professional-grade code introducing a new exception type should be treated with the same respect as a change in the method signature, i.e. be considered a breaking change. If you subscribe to this point of view then it's immediately obvious that going back to change (or verify) the client code is the only correct course of action.

For example, if Foo calls Bar, and Foo needs to stop processing regardless of the type of exception thrown by Bar, is there any advantage in being specific about the type of exception I'm catching?

Sure, because you will not be catching just exceptions thrown by Bar. There will also be exceptions that Bar's clients or even the runtime might throw during the time that Bar is on the call stack. A well-written Bar should define its own exception type if necessary so that callers can specifically catch the exceptions emitted by itself.

So what if I want to ignore every exception but OutOfMemoryException?

IMHO this is the wrong way to think about exception handling. You should be operating on whitelists (catch exception types A and B), not on blacklists (catch all exceptions apart from X).

3
  • It's often possible to specify an action which should be performed for all exceptions that indicate that an attempted operation failed with no side-effect, and or adverse implication about the state of the system. For example, if a user selects a document file to load, a program passes its name to a "create document object with data from a disk file" method, and that method fails for some particular reason the application hadn't anticipated (but which meets the above criteria), proper behavior should be to display an "Unable to load document" message rather than crashing the application.
    – supercat
    Commented Oct 15, 2018 at 21:27
  • Unfortunately, there is no standard means by which an exception can indicate the most important thing client code would want to know--whether it implies anything bad about the state of the system beyond what would be implied by the inability to perform the requested operation. Thus, even though situations where all exceptions should be handled are rare, there are thus many situations in which many exceptions should be handled the same way, and there's no criterion that is satisfied by all such exceptions would also be satisfied by some rare ones that should be handled differently.
    – supercat
    Commented Oct 15, 2018 at 21:33
  • It is not that hard to think of a catch block designed to work with ANY exception thrown: There is a fairly common situation with a catch block that wraps the exception in additional context information. You really do want to wrap all exceptions in this manner, and catching only some of them leaves open the possibility that in the future there will be new exceptions that are missed.
    – AgilePro
    Commented Apr 15 at 17:03
0

Maybe. There are exceptions to every rule, and no rule should be followed uncritically. You example might conceivably be one of the instances where it makes sense to swallow all exceptions. For example if you want to add tracing to a critical production system, and you want to make absolutely sure that you changes don't disrupt the main task of the app.

However, you should think carefully about possible reasons for failure before you decide to silently ignore them all. For example, what if the reason for the exception is:

  • a programming error in the logging method which causes it to always throw a particular exception
  • an invalid path to the logging file in the configuration
  • the disk is full

Don't you want to be notified immediately that this problem is present, so you can fix it? Swallowing the exception means you never know something went wrong.

Some problems (like the disk is full) might also cause other parts of the application to fail - but this failure is not logged now, so you never know!

1
  • I agree you never want to just swallow the exception. There is a fairly common situation with a catch block that wraps the exception in additional context information. You really do want to wrap all exceptions in this manner, and catching only some of them leaves open the possibility that in the future there will be new exceptions that are missed.
    – AgilePro
    Commented Apr 15 at 17:02
0

I would like to address this from a logical perspective rather than a technical one,

Now I have to change my code to handle that new exception.

Well, someone would have to handle it. That is the idea. Writers of library code would be prudent about adding new exception types though because it is likely to break clients, you should not encounter this very often.

Your question is basically "What if I don't care what went wrong? Do I really have to go through the hassle of finding out what it was?"

Here's the beauty part: no you do not.

"So, can I just look the other way and have whatever nasty thing pops up swept under the carpet automatically and be done with it?"

No, that is not how it works either.

The point is, the collection of possible exceptions is always larger than the collection you expect and are interested in in the context of your local little problem. You handle those you anticipate and if something unexpected happens, you leave it to the higher level handlers rather than swallowing it. If you do not care about an exception you did not expect, you bet someone up the call stack will and it would be sabotage to kill an exception before it reaches its handler.

"But... but... then one of those other exceptions I do not care about could cause my task to fail!"

Yes. But they will always be more important then the locally handled ones. Like a fire alarm or the boss telling you to stop what you are doing and pick up a more urgent task that popped up.

1
  • There is a fairly common situation with a catch block that wraps the exception in additional context information. You really do want to wrap all exceptions in this manner, and catching only some of them leaves open the possibility that in the future there will be new exceptions that are missed. This is not an example of simply looking the other way and sweeping under the carpet. Instead this is a catch block that is designed to handle any and all exceptions. There is nothing wrong with that.
    – AgilePro
    Commented Apr 15 at 17:02
-1

You should catch general exceptions at the top level of every process, and handle it by reporting the bug as well as possible and then terminating the process.

You should not catch general exceptions and try to continue execution.

1
  • I agree you should not catch and continue. Also agree you should at the root level catch all exceptions so that at a minimum they are logged.
    – AgilePro
    Commented Apr 15 at 17:04

Not the answer you're looking for? Browse other questions tagged or ask your own question.