Exception Handling With Tasks.WhenAll()

In a recent project IntelliTect developed for a client, we were working with an architecture that involved a client application communicating with an Azure app service, which communicated with a private on-premise web API service.  When attempting to transfer a very large file via a HttpResponse, we were hitting a failure that prevented the file from being downloaded.  Even though we have significant logging in place through our entire pipeline (client, middle tier, and on-premise server), we weren’t able to quickly identify the cause of the failure.  After further investigation of the Azure application events, we were able to see that some of our middle tier code in the Azure app service was failing.  The application event indicated that we hit a TaskCanceledException in one of our Azure app service apis.  This was very interesting, however, because we have extensive logging in our Azure app service that catches any exceptions thrown, and logs the exception information.  Our log file in this case, though, did not have any exceptions logged.

This got us to dig deeper, and we were able to quickly identify the reason for our missing log data.  In the client’s code, there was a method that had code similar to this:

public async Task Synchronize()
      List tasks = new List();
      Task task1 = SomeAsyncTask1();
      Task task2= SomeAsyncTask2();
      Task task3 = SomeAsyncTask3();
      await Task.WhenAll(tasks);
   catch (Exception ex)
      return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message);

As you can see from the code above, any exception in the catch handler should have been caught by the catch clause.  The code was not catching the exception, however, because the code was not written to use Task.WhenAll properly.  Task.WhenAll will not throw all exceptions when it encounters them.  Instead, it adds them to an AggregateException, that must be checked at the end of waiting for the tasks to complete. Note that the above code will throw the first exception that is encountered, but if there is more than 1, it will not catch all of them.  To correct the code, we wrote the following helper method:

private static Task WhenAllTasks(List tasks)
   Task allTasks = Task.WhenAll(tasks);
   catch (Exception ex)
      Trace.TraceError($"WhenAllTasks Exception: {ex.ToString()}");

   Trace.TraceInformation($"WhenAllTasks status: {allTasks.Status}");

   if (allTasks.Exception != null)
      throw allTasks.Exception;
   return allTasks;

This new code will now re-throw an AggregateException if one exists after waiting for the tasks to complete.  After adding this code, we were able to successfully track down which task in the client’s code was getting canceled, by viewing our logs.

For a full example, please download the following solution: http://intellitect.com/wp-content/uploads/2017/07/WhenAllTest.zip

Join the Conversation

  1. Erin Wissing
  2. Jason Peterson


Your email address will not be published. Required fields are marked *

  1. Statement about AggregateException is not correct. WhenAll returns pure Exception. What the hell blog is it??

  2. “As you can see from the code above, any exception in the catch handler should have been caught by the catch clause. The code was not catching the exception, however, because the code was not written to use Task.WhenAll properly.”

    This is not correct (or at least VERY misleading), as the catch clause WILL catch an exception thrown from await Task.WhenAll(…). I urge you to correct this, as this blog post is ranking amongst the top results on Google.

  3. Hello,
    You really shouldn’t call `.Wait()` with asynchronous code. That will block the thread!
    Please use `await allTasks` instead.

    1. Thank you for the comment. You are correct that this will block the thread, and we can call await allTasks instead. The key is checking t.Exception after awaiting it, and seeing if it is an aggregate exception that contains multiple exceptions.

  4. This post is very misleading and has in fact caused us a great deal of time wasted.
    awaiting Task.WhenAll *does in fact throw an exception* – the first its inner tasks’ exceptions.

    just build a demo project and see for yourself.

    1. Hi Yoav,

      Sorry you had difficulty with this. You are correct, that it does throw the first exception, I wasn’t quite clear on that. If there are multiple exceptions, it will not catch all of them, however. I’ve updated the blog post to indicate this, and uploaded a complete sample project that you can play around with if you want to.