1

I've seen a debate on this. Nested trys in the catch, I can see that being okay. The outer try has already triggered a catch by that time, hence no scope issues. The other way....hides errors (it is a scope issue).

try {

     try{
        Throws exception; 
        } catch (exception innerE) {
         outerE.printStackTrace(); /* I know the error , printing but have no way of passing what I know to the outer try*/
     }

} 

catch (exception outerE){
 outerE.printStackTrace(); /* Going to override the inner and not say anything because the inner catch is not visible to my scope */  
}

How is this not an anti-pattern?

  • 5
    The inner catch block can re-throw (and optionally wrap) the exception, if something needs to happen in the outer catch. Context can be passed through a wrapping exception if needed. – Mike Partridge Mar 27 at 13:30
  • It's an anitpattern if not used properly, for example double logging the error. But it can be used properly as @Mike points out. – Jon Raynor Mar 27 at 13:50
  • 1
    It's not popular enough to be an anti-pattern. – Erik Eidt Mar 27 at 15:03
  • 1
    You can pass the information just fine with an inner exception. Please clarify why you would consider this a scope issue. – Martin Maat Mar 28 at 8:47
6

There are proper uses of this pattern (as there are improper uses of it). As mentioned in the comments, additional information can be included by the inner catch:

try 
{
  try 
  {
    throw new GenericException("Generic message");
  }
  catch (Exception innerEx) 
    {
    // rollback some changes perhaps
    throw new MoreDetailedException(innerEx, "More details supplied here as well as by the type of exception");
  }
}
catch (Exception outerEx)
{
  Console.WriteLine(outerEx);
}

You can also use it to catch processing errors that you are able to recover from in your inner loop, and keep processing:

try 
{
  try 
  {
    _response = ProcessInputFromUser();
  }
  catch (Exception innerEx) 
  {
    _response = 0;
  }

  ProcessResponse(_response);
}
catch (Exception outerEx)
{
  Console.WriteLine(outerEx);
}

The improper way of handling this is to log the error twice, catch and simply rethrow, etc:

try 
{
  try 
  {
  }
  catch (Exception innerEx) 
  {
    Console.WriteLine(innerEx);
    throw;
  }
}
catch (Exception outerEx)
{
  Console.WriteLine(outerEx);
}
| improve this answer | |
  • A real world example of your second case: Try to process file A. If that doesn't work, try legacy file B. If that doesn't work, try really legacy file C. Only if none of them work do you return an error. That way if the someone was poking around in the archives and tried to examine an old job it still worked. – Loren Pechtel Apr 7 at 3:10
1

There's really not much difference between this and having a method that contains a try-catch called by another method with a try-catch. That is ubiquitous and not problematic (in itself) in any way. I would tend towards refactoring a nested try-catch into it's own method, when possible.

An example of when you might want to do something like this would be something like writing to a socket. If you were to encounter a socket disconnect, you probably just want to reconnect and try again (up to some limit.) However, if you encounter another error that you can't easily recover from, you want to handle it differently.

Again, from a readability perspective, it's generally best to move the nested portion into it's own method. But that's a mostly cosmetic change so I can't see how it would be a anti-pattern.

| improve this answer | |
1

Try/Catch clauses are fairly wordy, so while it is technically common to have nested try/catch blocks they are usually in different methods. Common places for performing nested try/catch blocks include:

  • Parsing a file where each line is a new record, while you may have failed records, you often want to pull as many records in as possible
  • Rendering loops where you don't necessarily want to kill the whole application if you can't update one element on screen

NOTE: example code is psuedo-code

In the case of bulk-parsing, you can have a loop that looks something like this:

try {
    foreach(var file in listOfFiles) {
        parseFile(file);
    }
}
catch (Exception e) {
    log.error("Stopped parsing all files due to unexpected error", e);
    notifyUser("Stopped parsing files");
}

And inside of parseFile() would be another try/catch:

private void parseFile(string fileName) throws ParseException, IOException {
    var lineNo = 0;

    using (var input = new TextReader(File.OpenRead(filename))) {
        foreach (var line in input.ReadLines()) {
            lineNo++;

            try {
                parseRecord(line);
            } catch (Exception e) {
                throw new ParseException(fileName, lineNo, e);
            }
        }
    }
}

This pattern may even be repeated for each field in the line if this is a regular structure. That said, you can see how the IOException bubbles up, and any internal exception while parsing a file can be wrapped so that we can provide additional context to make it easier to debug the parser.

More sophistication in the catch clause would allow us to determine if we simply log that exception and skip the record, or stop processing the file altogether.

Bottom line is that there are very good reasons to handle nested try/catch blocks. That does not mean every nested try/catch block is good. As with any error handling, you have to make sure the errors are being handled in an appropriate and predictable manner.

| improve this answer | |
0

(Comment converted into answer)


This section refers to nested try-catch blocks in general, i.e. not limited to the code sample verbatim.

In general, any function or pieces of code that performs multiple actions, and in which the error-handling / application state cleanup differs depending on which action / where in the code fails, the use of multiple try-catch blocks is necessary.

As other answers pointed out, the best coding style will extract these inner try-catch blocks into their own methods, and give these methods appropriate names that describe what they are "trying". In more complicated code, the method name should also become more wordy; they should describe what cleanup they are to perform.


This section refers to the code sample verbatim.

I suspect OP has a misunderstanding of how nested try-catch works.

When the innermost code block throws, it would be caught by the inner catch. To the extent that the inner catch block doesn't throw/rethrow, and doesn't inadvertently cause a different exception to be thrown, the outer catch will not catch anything.

Either the code sample is overly simplified - missing the rethrow, or that something is omitted (or indeed missing in the original code) that hinders our understanding of the code that OP has in mind.

Thus, the meaning of the outer catch block will need to be studied (researched) carefully, to identify whether there's any possible (no matter how unlikely) circumstances that would trigger the outer catch.

This is a justified case of leaving comments in the code. Such analysis is often time-consuming, and it is far from obvious.

Also, the circumstances that lead to the outer catch being triggered may be rare enough (such that a typical programmer might not even be aware of such possibility), but may have occurred frequent enough to earn a place in the issue-tracker. A comment should point out this possibility by pointing to the issue-tracker ticket, so that a programmer can know how to re-create the situation, in order to test that future code changes will continue to handle this rare situation correctly.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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