110

What does this mean and how to resolve it?

I am using TPL tasks.

The whole error

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.

at System.Threading.Tasks.TaskExceptionHolder.Finalize()

mscorlib

H.B.
  • 166,899
  • 29
  • 327
  • 400
Furkan Gözükara
  • 22,964
  • 77
  • 205
  • 342

2 Answers2

169

If you create a Task, and you don't ever call task.Wait() or try to retrieve the result of a Task<T>, when the task is collected by the garbage collector, it will tear down your application during finalization. For details, see MSDN's page on Exception Handling in the TPL.

The best option here is to "handle" the exception. This can be done via a continuation - you can attach a continuation to the task, and log/swallow/etc the exception that occurs. This provides a clean way to log task exceptions, and can be written as a simple extension method, ie:

public static void LogExceptions(this Task task)
{
    task.ContinueWith( t =>
    {
         var aggException = t.Exception.Flatten();
         foreach(var exception in aggException.InnerExceptions)
             LogException(exception);
    }, 
    TaskContinuationOptions.OnlyOnFaulted);
}

With the above, you can prevent any task from tearing down the app, and logging it, via:

Task.Factory.StartNew( () => 
   { 
       // Do your work...
   }).LogExceptions();

Alternatively, you can subscribe to the TaskScheduler.UnobservedTaskException and handle it there.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 20
    For added entertainment, have a static stub method `Off` in a class named as the four-letter word of your choice, and use this for your catch-all continuations. Helps to combat some of the pent-up frustration from this particular exception. – Aaronaught Oct 24 '11 at 23:27
  • actually this happened where i called a public static function inside of a tpl task. using try catch would solve this problem ? do i really need to create another task and wait it ? – Furkan Gözükara Oct 24 '11 at 23:34
  • @MonsterMMORPG: A try catch inside of the function (the public static) that caught the exception would handle it. The problem is that an exception is "bubbling up" to the task itself, and you're never waiting on the task to complete. If you do, it'll fix it. – Reed Copsey Oct 24 '11 at 23:35
  • so i need to handle the problem inside public static function or inside tpl task where i call the public static function ? i mean covering the public static function call inside try catch block inside tpl task would solve problem ? – Furkan Gözükara Oct 24 '11 at 23:38
  • 1
    @MonsterMMORPG Yes - You basically have to catch or handle the exception *somewhere*. As long as you handle it somewhere, your core problem will go away. – Reed Copsey Oct 25 '11 at 00:01
  • 1
    Isn't it possible that the task could throw an exception before the call to ContinueWith is made? – Tim Sylvester Aug 06 '12 at 23:45
  • 1
    @TimSylvester The framework will still map it through the continuation, even if it happens "before" the continuation is attached – Reed Copsey Aug 06 '12 at 23:49
  • @Reed Copsey Hi, having problems with yor approach here: http://stackoverflow.com/questions/11831844/unobservedtaskexception-being-throw-but-it-is-handled-by-a-taskscheduler-unobser – newway Aug 07 '12 at 11:16
  • Is it correct starting a task after logging of exception details? Baically continuation will log errors and restart tsk, or how it would be better to restart a task after failure? – sll Oct 25 '12 at 12:25
  • @ReedCopsey When I try to use this method in my class, I get an error on the .LogExceptions(); portion. It says: System.Threading.Tasks.Task does not contain a definition for LogExceptions. Instead of defining LogExceptions() in my class, and then trying to reference it like this, should I just put the .ContinueWith(...) call on the Task instead? – Mason G. Zhwiti Jul 30 '13 at 19:48
  • 1
    @MasonG.Zhwiti Extension methods must be defined within a static class, and the namespace has to be included (`using TheNamespace;`) – Reed Copsey Jul 31 '13 at 17:11
  • Good practice is returning Task object from the method to allow another tasks to be chained via ContinueWith() etc. – Jan Zahradník Mar 03 '14 at 09:55
  • 35
    Important note: This is only necessary for `.Net 4.0`. The exception handling was changed by default in `.net 4.5` to **not tear down the application**. See more in [Task Exception Handling in .NET 4.5](http://blogs.msdn.com/b/pfxteam/archive/2011/09/28/10217876.aspx) – i3arnon Jun 22 '14 at 09:27
  • I've tried this approach, but still have this exception in string `foreach (var exception in aggException.InnerExceptions)` – monstr Sep 15 '14 at 06:09
  • As an additional note, I was getting this exception was happening inside of an `async` method, but that method was not being called with an `await`. Since it wasn't being awaited (improperly) the task failed but there was nothing holding on to it or observing it. – KallDrexx Nov 13 '17 at 20:19
47

Sure; it means a Task got finalized after being left to garbage collection, but the task itself failed. There are two fixes:

  • handle the tasks fail directly (use ContinueWith(...) to subscribe, and check .IsFaulted and .Exception on the Task in the parameter)
  • handle the TaskScheduler.UnobservedTaskException event, and mark it observed (call e.SetObserved() after logging the error)
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 4
    +1 - With one addition - if your continuation is doing nothing but checking the `IsFaulted`, you can use the `OnlyOnFaulted` continuation option and avoid the manual check... – Reed Copsey Oct 24 '11 at 23:26
  • actually this happened where i called a public static function inside of a tpl task. using try catch would solve this problem ? do i really need to create another task and wait it ? thanks – Furkan Gözükara Oct 24 '11 at 23:34
  • 5
    +1 for mentioning that `SetObserved` on `UnobservedTaskExceptionEventArgs` needs to be called. – James Webster Apr 20 '12 at 03:44
  • A reminder that setting OnlyOnFaulted will mean that the OnlyOnFaulted task will be marked as Cancelled if the task it is attached to does not fault. And Cancellation status comes with its own headaches. – Robert Christ Jan 27 '23 at 19:23