Find the inner-most exception without using a while loop?

45,913

Solution 1

Oneliner :)

while (e.InnerException != null) e = e.InnerException;

Obviously, you can't make it any simpler.

As said in this answer by Glenn McElhoe, it's the only reliable way.

Solution 2

I believe Exception.GetBaseException() does the same thing as these solutions.

Caveat: From various comments we've figured out it doesn't always literally do the same thing, and in some cases the recursive/iterating solution will get you further. It is usually the innermost exception, which is disappointingly inconsistent, thanks to certain types of Exceptions that override the default. However if you catch specific types of exceptions and make reasonably sure they're not oddballs (like AggregateException) then I would expect it gets the legitimate innermost/earliest exception.

Solution 3

Looping through InnerExceptions is the only reliable way.

If the caught exception is an AggregateException, then GetBaseException() returns only the innermost AggregateException.

http://msdn.microsoft.com/en-us/library/system.aggregateexception.getbaseexception.aspx

Solution 4

If you don't know how deep the inner exceptions are nested, there is no way around a loop or recursion.

Of course, you can define an extension method that abstracts this away:

public static class ExceptionExtensions
{
    public static Exception GetInnermostException(this Exception e)
    {
        if (e == null)
        {
            throw new ArgumentNullException("e");
        }

        while (e.InnerException != null)
        {
            e = e.InnerException;
        }

        return e;
    }
}

Solution 5

I know this is an old post, but I'm surprised nobody suggested GetBaseException() which is a method on the Exception class:

catch (Exception x)
{
    var baseException = x.GetBaseException();
}

This has been around since .NET 1.1. Documentation here: http://msdn.microsoft.com/en-us/library/system.exception.getbaseexception(v=vs.71).aspx

Share:
45,913
Daniel T.
Author by

Daniel T.

Updated on March 07, 2020

Comments

  • Daniel T.
    Daniel T. about 4 years

    When C# throws an exception, it can have an inner exception. What I want to do is get the inner-most exception, or in other words, the leaf exception that doesn't have an inner exception. I can do this in a while loop:

    while (e.InnerException != null)
    {
        e = e.InnerException;
    }
    

    But I was wondering if there was some one-liner I could use to do this instead.

  • Jay
    Jay over 12 years
    +1 There is nothing like knowing the BCL to avoid convoluted solutions. Clearly, this is the most correct answer.
  • codingoutloud
    codingoutloud almost 11 years
    GetBaseException() method does this w/o a loop. msdn.microsoft.com/en-us/library/…
  • Tarik
    Tarik almost 11 years
    For some reason, GetBaseException() didn't return the very first root exception.
  • Tarik
    Tarik almost 11 years
    This works whereas Exception.GetBaseException() didn't for me.
  • Josh Sutterfield
    Josh Sutterfield over 10 years
    Glenn McElhoe pointed out that indeed GetBaseException() does not always do what MSDN suggests we can expect in general (that "the Exception that is the root cause of one or more subsequent exceptions"). In AggregateException it is limited to the lowest exception of the same type, and perhaps there are others.
  • Josh Sutterfield
    Josh Sutterfield over 10 years
    Good catch. Thanks - that explains the comments above where that answer was not working for some people. This makes it clear that MSDN's general description of "root cause of one or more subsequent exceptions" is not always what you'd assume since derived classes may override it. The real rule seems to be that all exceptions in a chain of exceptions "agree" on GetBaseException() & return the same object, which seems to be the case for AggregateException.
  • Giovanni B
    Giovanni B about 9 years
    Doesn't work for my issue. I have a few more levels down than what this is providing.
  • Michael R
    Michael R almost 9 years
    I used this ex.GetBaseException().GetBaseException().GetBaseException() to get to the deeptest exception.
  • Chris Ballance
    Chris Ballance over 8 years
    GetBaseException() did not work for me, because the top-most exception is an AggregateException.
  • Kiquenet
    Kiquenet over 8 years
    Useful public static Exception GetOriginalException(this Exception ex) { if (ex.InnerException == null) return ex; return ex.InnerException.GetOriginalException(); }
  • Federico Navarrete
    Federico Navarrete about 6 years
    Thanks for your solution! Few people think in VB :D
  • Yoda
    Yoda about 6 years
    And there's a reason why! :P
  • Kiquenet
    Kiquenet about 6 years
    What's about Exception.GetBaseException() ?
  • Kiquenet
    Kiquenet about 6 years
    Not applies AggregateException.InnerExceptions ?
  • armadillo.mx
    armadillo.mx almost 6 years
    Indeed was indicated before on December 5, 2012
  • Mohammad Reza Sadreddini
    Mohammad Reza Sadreddini over 2 years
    Wouldent this code change the "e" source exception? and Shouldnt we make a copy of "e" before assigning InnerException to it? I suggest: var copyOfException = e; while (copyOfException.InnerException != null) copyOfException = copyOfException.InnerException;
  • Josh Sutterfield
    Josh Sutterfield over 2 years
    Honestly with AggregateException there is no base exception per se, because there are multiple exceptions, each having a base exception. You would almost need a new AggregateException strictly reflecting the base exceptions of each exception in the original AggregateException. But that's not a real thrown exception. For AggregateException the ideal call would be plural, i.e. Exception[] GetBaseExceptions() but that's not a thing.