When does Task.Run(Action, CancellationToken) throw TaskCanceledException?

.net, c#, task-parallel-library

Solution

There seems to be some confusion (and the documentation might be misleading).

Inoking the `Task.Run` method would never throw `TaskCanceledException` (at least with the current implementation). Unlike `ArgumentNullException` and `ObjectDisposedException` that are thrown synchronously when the "The action parameter was null" and "The CancellationTokenSource associated with cancellationToken was disposed." respectively.

`Task.Run` however returns a `Task` that may be canceled using the `CancellationToken` parameter (more on cancellation in here) and waiting on it with `await task`, `task.Wait()`, `task.Result`, etc. would throw a `TaskCanceledException` (possibly wrapped in an `AggregateException`)

Task<int> task = null;
try
{
    task = Task.Run(() => 5, new CancellationToken(true));
}
catch (TaskCanceledException)
{
    Console.WriteLine("Unreachable code");
}

try
{
    int result = await task;
}
catch (TaskCanceledException)
{
    Console.WriteLine("Awaiting a canceled task");
}

It might be clearer if the documentation had 2 sections of possible exceptions:

- "regular" synchronous exceptions (e.g. `ArgumentNullException` and `ObjectDisposedException`)

- "async" asynchronous exceptions that could only be thrown by waiting on the returned task (e.g. `TaskCanceledException`)

Problem

According to documentation `Task.Run(Action, CancellationToken)` throws `TaskCanceledException` when the task has been canceled. When exactly does `Task.Run(Action, CancellationToken)` throw `TaskCanceledException`? It is not clear what conditions must be met for this exception to be thrown.

Original source