Why should you avoid `async void`?

C# Async & Concurrency Advanced 3–5 Yrs5+ Yrs Debugging 1 min read

Quick Answer

async void can't be awaited, so callers can't know when it finishes or catch its exceptions — an unhandled exception in an async void method crashes the process (it's raised on the sync context). Only use it for event handlers, which the framework requires; otherwise return Task.

The problem with async void is that nothing can await it, so the caller has no idea when it's done and — more importantly — can't catch its exceptions. An unhandled exception in an async void method doesn't get captured in a Task; it gets thrown on the synchronization context and usually takes the process down. So the only legitimate use is an event handler, where the signature has to be void. Even then I wrap the body in a try/catch. Anything else returns Task.

  • async Task — awaitable, exceptions captured in the returned Task, testable.
  • async void — no way to await; exceptions propagate to the SynchronizationContext and typically become an unhandled exception.
  • Event handlers must be void to match the delegate — keep them thin: async void Button_Click(...) { try { await DoWorkAsync(); } catch { ... } }.
  • “Fire and forget” should still return Task and be handled deliberately (e.g. _ = DoWorkAsync().ContinueWith(LogFailures)), not async void.