Exception Handling with async (try/catch with async)
Explains how to use try / catch / finally inside async methods (async / await) to properly catch and handle exceptions, along with async-specific considerations.
Syntax
using System;
using System.Threading.Tasks;
// Basic syntax for using try/catch inside an async method.
static async Task AsyncMethod()
{
try
{
await AsyncOperation();
}
catch (ExceptionType ex)
{
// Handle the exception.
}
finally
{
// Always runs, whether or not an exception occurred.
}
}
// When running multiple tasks in parallel with Task.WhenAll(), watch out for AggregateException.
try
{
await Task.WhenAll(task1, task2, task3);
}
catch (Exception ex)
{
// With WhenAll, only the first exception is caught.
}
Method List
| Syntax / Property | Description |
|---|---|
| try { await ... } catch (...) | Wrapping an await expression in a try block lets you catch exceptions from async operations using a normal catch clause. |
| AggregateException | An exception type that bundles multiple exceptions together, thrown when multiple tasks fail — such as with Task.WhenAll(). |
| Task.Exception | A property that holds an AggregateException when a task has faulted. |
| OperationCanceledException | The exception thrown when an operation is canceled via a CancellationToken. |
Sample Code
using System;
using System.Threading.Tasks;
class Program
{
// An async method that throws an exception.
static async Task<int> DivideAsync(int numerator, int denominator)
{
await Task.Delay(100); // Simulates async processing.
if (denominator == 0)
throw new DivideByZeroException("Cannot divide by zero.");
return numerator / denominator;
}
// Runs multiple tasks in parallel and handles exceptions.
static async Task ParallelSample()
{
Task<int> task1 = DivideAsync(10, 2);
Task<int> task2 = DivideAsync(20, 0); // This one will throw an exception.
Task<int> task3 = DivideAsync(30, 3);
// Wait for all tasks to complete.
Task<int[]> whenAll = Task.WhenAll(task1, task2, task3);
try
{
int[] results = await whenAll;
}
catch
{
// Enumerate the inner exceptions from AggregateException.
if (whenAll.Exception != null)
{
foreach (Exception ex in whenAll.Exception.InnerExceptions)
{
Console.WriteLine($"Exception: {ex.Message}");
}
}
}
}
static async Task Main()
{
// Basic try/catch/finally usage.
try
{
int result = await DivideAsync(10, 2);
Console.WriteLine($"Result: {result}");
int error = await DivideAsync(10, 0); // This will throw an exception.
}
catch (DivideByZeroException ex)
{
Console.WriteLine($"Divide by zero error: {ex.Message}");
}
finally
{
Console.WriteLine("The finally block has executed.");
}
// Parallel execution sample.
await ParallelSample();
}
}
Overview
When you place an await expression inside a try block in an async method, any exception thrown during the async operation can be caught normally with catch. Exceptions thrown inside an async void method cannot be caught and will crash the application. Avoid using async void outside of event handlers.
With Task.WhenAll(), awaiting the result will only surface the first exception even if multiple tasks fail. To inspect all exceptions, access task.Exception.InnerExceptions. For the basics of exception handling, see try / catch / finally. For the basics of async programming, see async / await.
If you find any errors or copyright issues, please contact us.