High-Performance .NET: Async, Multithreading, and Parallel Programming PLINQ Created: 20 Jan 2026 Updated: 20 Jan 2026

Error Handling in PLINQ

Writing parallel code is not just about speed; it's about reliability. When a standard LINQ query fails, it throws a single exception and stops. In Parallel LINQ (PLINQ), multiple operations happen simultaneously on different threads. This means that instead of one error, you might encounter several different errors at the exact same moment.

To build production-ready applications, you must master the unique way PLINQ communicates failure.

1. The AggregateException: The Error Container

When one or more threads in a PLINQ query encounter an error, PLINQ doesn't throw those exceptions immediately. Instead, it waits for the other threads to reach a stopping point, collects all the errors, and wraps them inside an AggregateException.

To handle this, you need to catch the AggregateException and inspect its InnerExceptions property to understand what went wrong across all cores.

Example: Catching Multiple Failures

var numbers = Enumerable.Range(-5, 10); // Includes negative numbers

try
{
var results = numbers.AsParallel()
.Select(n => {
if (n < 0) throw new ArgumentException($"Negative value: {n}");
return Math.Sqrt(n);
})
.ToList();
}
catch (AggregateException ae)
{
// Flatten() is useful if there are nested exceptions
foreach (var ex in ae.Flatten().InnerExceptions)
{
Console.WriteLine($"Caught error: {ex.Message}");
}
}

2. Handling Cancellation Separately

There is one major exception to the AggregateException rule: OperationCanceledException.

If you provide a CancellationToken using .WithCancellation() and the token is triggered, PLINQ will shut down the worker threads as quickly as possible. This specific exception is usually thrown directly (not wrapped) to signify that the query was stopped intentionally, not because of a bug.

Example: Managing Timeouts and Cancellation

var cts = new CancellationTokenSource();
cts.CancelAfter(50); // Stop after 50ms

try
{
var largeData = Enumerable.Range(1, 10_000_000)
.AsParallel()
.WithCancellation(cts.Token)
.Where(n => n % 2 == 0)
.ToList();
}
catch (OperationCanceledException)
{
Console.WriteLine("Query was cancelled by the user or system timeout.");
}
catch (AggregateException ae)
{
Console.WriteLine("A logical error occurred during parallel execution.");
}

3. Element-Level Resilience

Sometimes, you don't want the entire query to crash just because one item failed (e.g., a single failed API call in a list of 1,000). In these cases, you should handle the error inside the query projection rather than letting it bubble up to the AsParallel() engine.

Example: "Soft Fail" Strategy

var urls = new[] { "site1.com", "broken-site.com", "site2.com" };

var processedResults = urls.AsParallel()
.Select(url => {
try
{
return DownloadData(url); // Imagine this is a heavy method
}
catch (Exception)
{
// Log the error and return a default value or null
return "Error: Failed to fetch";
}
}).ToList();

4. Best Practices for PLINQ Error Handling

  1. Always use Flatten(): If your parallel query calls other parallel tasks, exceptions can become deeply nested. ae.Flatten() simplifies them into a single-level list.
  2. Catch OperationCanceledException First: In your catch blocks, place the cancellation catch above the AggregateException catch.
  3. Log Everything: Since parallel bugs are harder to reproduce, always log the full stack trace of every inner exception.
  4. Consider Degree of Parallelism: If you are hitting an external resource (like a database) that is throwing "Too Many Connections" errors, use .WithDegreeOfParallelism() to limit the number of simultaneous requests.

Summary Checklist

Exception TypeReasonHandling Strategy
AggregateExceptionOne or more threads failed.Use .Flatten() and iterate InnerExceptions.
OperationCanceledExceptionToken was signaled or timeout reached.Catch separately to handle graceful shutdowns.
Local try-catchTransient errors (Network/IO).Wrap logic inside .Select() to prevent query termination.
Share this lesson: