How to re-throw an exception - C#

When we catch an exception, we could throw another exception within the catch block. This could be the same type of exception, or a different type altogether.

By throwing an exception within a catch block, we're assuming that a method higher up the call stack will handle it correctly.

This process is called re-throwing an exception.

Extending a previous example

In the previous article, we looked at [how to catch exceptions](/post/how to catch exceptions).

Let's look at the example from that article:

public static void Main (string[] args) 
{
	try
	{
		PrintName(null);
	}
	catch(NullReferenceException e)
	{
		Console.WriteLine("No name was supplied!");
	}
	catch(ArgumentException e)
	{
		Console.WriteLine($"We were unable to get your name!");
	}

	Console.WriteLine("Goodbye!");
}

static void PrintName(string name)
{
	if(name == null)
	{
		throw new NullReferenceException("Name is null");
	}

	if(name.Length == 0)
	{
		throw new ArgumentException("Name should not be empty");
	}

	Console.WriteLine($"Hello {name}!");
}

The try, catch around PrintName handles both scenarios where an exception is thrown due to null, or an empty string being supplied.

Now let's create a third scenario where we might throw an exception:

static void PrintName(string name)
{
	if(name == null)
	{
		throw new NullReferenceException("Name is null");
	}

	if(name.Length == 0)
	{
		throw new ArgumentException("Name should not be empty");
	}
	
	if(name.Length > 100)	{		throw new Exception("Name is far too long!");	}
	Console.WriteLine($"Hello {name}!");
}

There is nothing wrong with having a name larger than 100 characters, however we may find that our application isn't able (or the developer doesn't want) to support it.

So what happens if we call PrintName now, with a large name?

try
{
	PrintName("Daenerys Stormborn of House Targaryen, the First of Her Name, Queen of the Andals and the First Men, Protector of the Seven Kingdoms, the Mother of Dragons, the Khaleesi of the Great Grass Sea, the Unburnt, the Breaker of Chains");
}
catch(NullReferenceException e)
{
	Console.WriteLine("No name was supplied!");
}
catch(ArgumentException e)
{
	Console.WriteLine($"We were unable to get your name!");
}
Unhandled Exception:
System.Exception: Name is far too long!
  at CatchingExceptions.PrintName (System.String name) [0x00034] in <d7e559a4b3ad4ecf935f89c41dd17607>:0 
  at CatchingExceptions.Main (System.String[] args) [0x00000] in <d7e559a4b3ad4ecf935f89c41dd17607>:0 

We now need to catch and handle this exception.

But what if we don't want to handle it at this point? It may make more sense to handle the exception at a higher level.

Alternatively, we might want to take some initial corrective action, and then perform the rest of the handling higher up the call stack.

To do this, we need to re-throw the exception.

Re-throwing an exception

Let's refactor the example to show a scenario where an exception might be re-thrown:

public static void Main (string[] args) 
{
	try
	{
		GreetName("Daenerys Stormborn of House Targaryen, the First of Her Name, Queen of the Andals and the First Men, Protector of the Seven Kingdoms, the Mother of Dragons, the Khaleesi of the Great Grass Sea, the Unburnt, the Breaker of Chains");
	}
	catch(Exception e)
	{
		Console.WriteLine($"Could not greet because - {e.Message}");
	}
}

static void GreetName(string name)
{
	try
	{
		PrintName(name);
	}
	catch(NullReferenceException e)
	{
		Console.WriteLine("No name was supplied!");
	}
	catch(ArgumentException e)
	{
		Console.WriteLine($"We were unable to get your name!");
	}
	catch
	{
		Console.WriteLine("Unable to greet you!")
		// This exception isn't handled here, throw it again
		// It is hopefully handled further up!
		throw;
	}

	Console.WriteLine("Goodbye!");
}

static void PrintName(string name)
{
	if(name == null)
	{
		throw new NullReferenceException("Name is null");
	}

	if(name.Length == 0)
	{
		throw new ArgumentException("Name should not be empty");
	}

	if(name.Length > 100)
	{
		throw new Exception("Name is far too long!");
	}

	Console.WriteLine($"Hello {name}!");
}

The exception thrown by having a name greater than 100 characters is still thrown in PrintName, however GreetName doesn't know how to handle it.

By throwing it again, we are assuming something higher up the call stack will handle it appropriately.

Unable to greet you!
Could not greet because - Name is far too long!

Why bother re-throwing?

We could have omitted the catch, throw in PrintName entirely, and the exception would still have been caught in Main.

So why re-throw it?

A common reason is to handle part of the exception, before throwing it up the call stack to handle it again.

In our example, we wrote two lines to the console. The first was called in PrintName, whereas the second was called in Main.

In a real-life scenario, you may find that it makes more sense for a method to handle some of the responsibility of a caught exception, and for the calling method to handle the rest.