The AggregateException I catch does not have the exception I expect

.net, c#, exception, task-parallel-library

Solution

Let's simplify your code a bit:

var t1 = Task.Factory.StartNew(a1);
var t2 = t1.ContinueWith(a2, TaskContinuationOptions.NotOnFaulted);
var t3 = t2.ContinueWith(a3, TaskContinuationOptions.NotOnFaulted);

t3.Wait();

Now assume that `a1` throws an exception. What happens is that `t1` becomes faulted (`t1.Status == TaskStatus.Faulted`). Because of that, `t2` can't run (because of `NotOnFaulted`) and so it will be canceled. But this is not what you presumably expected: `t2` won't be faulted, it will be canceled (`t2.Status == TaskStatus.Canceled`). But this means that `t3` can run normally, and if it doesn't throw, `t3.Wait()` won't throw any exception.

How to fix this? First, you probably shouldn't use `TaskContinuationOptions.NotOnFaulted`, but `TaskContinuationOptions.OnlyOnRanToCompletion` instead. But that doesn't solve the problem of “disappearing” exceptions. To solve that, I see two possibilities:

Call `Wait()` at the beginning of each continuation and don't use any `TaskContinuationOptions`. This means you might get some exception wrapped in `AggregateException`, which is itself wrapped in `AggregateException`, which is wrapped in another `AggregateException`, etc. To solve this, you could use `Flatten()` or `Handle()`.

Wait for all the tasks, by using `Task.WaitAll()`. `WaitAll()` will throw an `AggregateException` that will contain the original exception and also `TaskCanceledException` for each of the tasks that were canceled because of the first exception.

Problem

I am using the Task Parallel Library to set up a chain of Tasks as shown below but I am getting an odd exception handling experience that I don't understand. I use Parallel.ForEach and invoke an Action which includes a call to the following method. This Parallel.ForEach is wrapped in a try...catch(AggregateException) and when an exception occurs - as it does in one of the Parallel branches - a SchemaValidation exception then I would expect to see that in the AggregateException. However, what I get is 'A task was canceled' - TaskCanceledException. Where has my SchemaValidationException gone? ``` private static void ProcessChunk(Task<ISelectedChunk> selectionTask, IRepository repository, IIdentifiedExtractChunk identifiedExtractChunk, IBatchRunConfiguration batchRunConfiguration, IBatchRun batchRun, ILog log, IAuthenticationCertificate authenticationCertificate, IFileSystem fileSystem, long batchRunRid) { var transformationTask = selectionTask.ContinueWith(TransformationFunction.Transformation(identifiedExtractChunk, batchRunConfiguration, batchRun), TaskContinuationOptions.NotOnFaulted); var schemaValidationTask = transformationTask.ContinueWith(SchemaValidationFunction.SchemaValidationTask(batchRunConfiguration), TaskContinuationOptions.NotOnFaulted); var compressTask = schemaValidationTask.ContinueWith(CompressFunction.CompressTask(identifiedExtractChunk), TaskContinuationOptions.NotOnFaulted); var encryptTask = compressTask.ContinueWith(EncryptionFunction.EncryptTask(authenticationCertificate), TaskContinuationOptions.NotOnFaulted); var fileGenerationTask = encryptTask.ContinueWith(FileGenerationFunction.FileGenerationTask(identifiedExtractChunk, batchRunConfiguration, fileSystem), TaskContinuationOptions.NotOnFaulted); // Take the time before we start the processing DateTime startBatchItemProcessing = DateTime.Now; // Start with the Selection Task selectionTask.Start(); // And wait on the last task in the chain fileGenerationTask.Wait(); // Take the time at the end of the processing DateTime endBatchItemProcessing = DateTime.Now; // Record all the relevant information and add it to the collection IBatchChunkProcessed batchChunkProcessed = GetBatchItemProcessed(identifiedExtractChunk, batchRunRid, fileGenerationTask.Result, transformationTask.Result.Item2, startBatchItemProcessing, endBatchItemProcessing); BatchItemsProcessed.Add(batchChunkProcessed); ```

Original source