Skip to content

Capturing and rethrowing with original stack trace

Context: Using ExceptionDispatchInfo, you can capture an exception and later rethrow it without losing the original stack trace. This is different from throw ex; (which resets the stack) and throw; (which only works inside the original catch block). It is especially valuable when exceptions cross thread or async boundaries.

using System;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
ExceptionDispatchInfo info = null;
try
{
await Task.Run(() => throw new ArgumentException("Bad argument"));
}
catch (ArgumentException ex)
{
info = ExceptionDispatchInfo.Capture(ex);
}
// Later (possibly in another method)
try
{
info?.Throw();
}
catch (ArgumentException ex)
{
Console.WriteLine($"Rethrown: {ex.Message}");
Console.WriteLine(ex.StackTrace);
}
}
}
Terminal window
dotnet run
Rethrown: Bad argument
at Program.<>c.<Main>b__0_0() in ...
at System.Threading.Tasks.Task`1.InnerInvoke()
...
  • The captured exception’s original stack trace is preserved.
  • You can store the ExceptionDispatchInfo in a field or collection.
  • Avoid capturing the same exception multiple times (it works, but unnecessary).

AggregateException handling – When flattening AggregateException in parallel loops, capture each inner exception and rethrow later.
See .NET docs on rethrowing exceptions.