Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task Continuation (OnlyOnFaulted) still gets unobserved exception

I have a task with a continuation to handle errors:

var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var loadTask = Task<List<OrderItemViewModel>>.Factory.StartNew(() =>
{
       throw new Exception("derp");
});

var errorContinue = loadTask.ContinueWith(t =>
    {
        MainViewModel.RemoveViewModel(this);
    }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, uiScheduler);

The continuation is hit, but a few seconds later I receive this error in the application:

A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.

Is this related to the uiScheduler? The solution to the similar question is basically what I'm doing A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was

like image 598
Chris Klepeis Avatar asked Sep 08 '12 01:09

Chris Klepeis


People also ask

What is unobserved task exception?

An “unobserved” exception is one that's stored into the task but then never looked at in any way by the consuming code. There are many ways of observing the exception, including Wait()'ing on the Task, accessing a Task<TResult>'s Result, looking at the Task's Exception property, and so on.

How to handle Exceptions in Task?

Exceptions are propagated when you use one of the static or instance Task. Wait methods, and you handle them by enclosing the call in a try / catch statement. If a task is the parent of attached child tasks, or if you are waiting on multiple tasks, multiple exceptions could be thrown.

Does await throw AggregateException?

When using await, it's going to unwrap the first exception and return it, that's why we don't hit the catch (AggregateException e) line. But if we use something like the below code sample, we catch the AggregateException , note that it's not a good idea since we're blocking the running thread.


1 Answers

You need to actually handle (or at least observe) the exception:

var errorContinue = loadTask.ContinueWith(t =>
{
    // Observe/acknowledge the exception.  
    // You can use t.Wait(), which throws, or just grab the exception
    var exception = t.Exception; 
    MainViewModel.RemoveViewModel(this);
}, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, uiScheduler);

This is because of this line of the documentation on exception handling in the TPL:

If you do not wait on a task that propagates an exception, or access its Exception property, the exception is escalated according to the .NET exception policy when the task is garbage-collected.

In your case, you have a continuation, but you never actually "wait on the exception" or access it's exception property. The reason my answer (in the related question you posted) works is that I'm actually using the Exception property on the Task passed through the continuation.

like image 191
Reed Copsey Avatar answered Oct 12 '22 14:10

Reed Copsey