Swimburger

Rethrowing your exceptions wrong in .NET could erase your stacktrace

Niels Swimberghe

Niels Swimberghe - - .NET

Follow me on Twitter, buy me a coffee

You may be erasing your stacktrace if you are catching and rethrowing exceptions the wrong way. This could make debugging a nightmare because you don't know where the exception was originally thrown.
You are erasing parts of the stacktrace if you are catching and rethrowing exceptions like this:

try
{
    DoWork();
}
catch (Exception ex)
{
    throw ex;
}

If you catch the rethrown exception and print out the stacktrace, you will notice that there's no mention of the DoWork method where the exception was originally thrown.

System.Exception: Exception of type 'System.Exception' was thrown.
    at CatchRethrow.Program.IncorrectCatchAndReThrow() in /home/azureuser/CatchRethrow/Program.cs:line 50
    at CatchRethrow.Program.Main(String[] args) in /home/azureuser/CatchRethrow/Program.cs:line 22

That's because it was overwritten when the exception was rethrown.
The correct syntax is to use throw; instead of throw ex;:

try
{
    DoWork();
}
catch (Exception ex)
{
    throw;
}

If you catch the rethrown exception now and print out the stacktrace, the DoWork method is printed as part of the stacktrace: 

System.Exception: Exception of type 'System.Exception' was thrown.
    at CatchRethrow.Program.DoWork() in /home/azureuser/CatchRethrow/Program.cs:line 56
    at CatchRethrow.Program.CorrectCatchAndThrow() in /home/azureuser/CatchRethrow/Program.cs:line 34
    at CatchRethrow.Program.Main(String[] args) in /home/azureuser/CatchRethrow/Program.cs:line 12

Luckily, there's a code analysis rule "CA2200: Rethrow to preserve stack details" that will warn you about this. 
Here's the full sample of the code used to demonstrate the issue above:

using System;

class Program
{
    static void Main(string[] args)
    {
        // correct catch/throw
        try
        {
            CorrectCatchAndThrow();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
            /*
            System.Exception: Exception of type 'System.Exception' was thrown.
                at CatchRethrow.Program.DoWork() in /home/azureuser/CatchRethrow/Program.cs:line 56
                at CatchRethrow.Program.CorrectCatchAndThrow() in /home/azureuser/CatchRethrow/Program.cs:line 34
                at CatchRethrow.Program.Main(String[] args) in /home/azureuser/CatchRethrow/Program.cs:line 12
            */
        }

        // incorrect catch/throw
        try
        {
            IncorrectCatchAndReThrow();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
            /*
            System.Exception: Exception of type 'System.Exception' was thrown.
                at CatchRethrow.Program.IncorrectCatchAndReThrow() in /home/azureuser/CatchRethrow/Program.cs:line 50
                at CatchRethrow.Program.Main(String[] args) in /home/azureuser/CatchRethrow/Program.cs:line 22
            */
        }
    }

    static void CorrectCatchAndThrow()
    {
        try
        {
            DoWork();
        }
        catch (Exception ex)
        {
            throw;
        }
    }

    static void IncorrectCatchAndReThrow()
    {
        try
        {
            DoWork();
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    static void DoWork()
    {
        throw new Exception();
    }
}

Related Posts

Related Posts