Swimburger

Rethrowing your exceptions wrong in .NET could erase your stacktrace

Niels Swimberghe

Niels Swimberghe - - .NET

Follow me on X, 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 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();
    }
}