Why Your async void Handler Is Swallowing Exceptions
An async void method cannot be awaited, so any exception it throws escapes to the synchronization context and takes the process down. Here is what actually happens and what to write instead.
On this page
Most C# developers learn early that async void is bad, and most stop there. The reason it's bad is more specific and more interesting than "avoid it."

What actually happens
When you mark a method async Task, the compiler hands you a Task that captures any exception thrown inside. Awaiting that task rethrows it at the call site, where your try/catch can see it.
async void returns nothing. There is no task, so there is nowhere to put the exception. The compiler instead posts it to the current SynchronizationContext, and in ASP.NET Core there isn't one — so it lands on the thread pool as an unobserved exception and terminates the process.
// Wrong: the exception escapes and kills the process
public async void SendWelcomeEmail(string address)
{
await _mailer.SendAsync(address); // throws → process down
}
// Right: the caller can await, observe, and handle
public async Task SendWelcomeEmailAsync(string address)
{
await _mailer.SendAsync(address);
}
The catch block that never runs
This is the part that surprises people:
try
{
SendWelcomeEmail(address); // returns immediately
}
catch (SmtpException)
{
// never reached — the method returned before it threw
}
The call returns at the first await, long before the exception exists. The catch has already gone out of scope by the time anything goes wrong.
The one legitimate exception
Event handlers. An event signature is void, so async void is the only option:
button.Click += async (sender, args) => await LoadDataAsync();
Even here, wrap the body in try/catch yourself. Nothing else will.
What to do instead
- Return
Taskfrom every async method that isn't an event handler - For fire-and-forget work, use a hosted service or a queue, not a discarded task
- Enable the analyzer:
VSTHRD100flagsasync voidat build time - See the official guidance on async best practices for the full picture
If you're auditing an existing codebase, search for async void and expect most hits to be bugs nobody has triggered yet.