In a previous post we discussed about parallel VS serial execution of asynchronous operations. This time instead we’ll see how to properly do exception handling in parallel Tasks.

Let’s suppose you have a bunch of network calls to do, maybe to some microservices. Maybe you’re in an API Gateway and you’re aggregating data.

The calls have no dependencies between each other and can be executed in parallel. So what do you do? You wrap the calls in Task.WaitAll() or, even better, in Task.WhenAll() . Something like this:

Task.WhenAll() returns another Task that can be awaited so we don’t block the current thread. Nice and clean.

Now! Suppose one or all the async operations fail and throw. How would you handle it? Try/catch is a good start:

That works fine, in case you have a single exception. If more than one async operation fails, Task.WhenAll() will give you visibility only of the first one. That’s one of the main differences with Task.WaitAll() : this one instead will collect all the exceptions and re-throw an AggregateException.

So what can we do? Go back to Task.WaitAll() ? Nah.

The trick is to not await directly the call to Task.WhenAll() but to store instead the returned Task in a variable. In the try/catch block then we can access the task.Exception property, which is an AggregateException, and do whatever we want with its InnerExceptions:

As usual I’ve pushed a small repo on GitHub. It’s a small dotNET Core console app which runs a bunch of tasks in parallel and shows how to trap the exceptions.