dotnet/reactive · error · AggregateException
One or more errors occurred.
Error message
One or more errors occurred.
What it means
Merge concurrently iterates multiple source async sequences into one. If any source fails, Merge waits for all sources to finish cleanup, then throws an AggregateException containing every exception observed, rather than just the first one. This preserves all failures from concurrently-running sequences (similar to throwing from a finally block).
Solutions
- Unwrap errors.InnerExceptions (catch AggregateException) and inspect each faulting source; add per-source error handling (e.g. .Catch() on individual streams) before merging.
- Ensure each source sequence itself cannot throw (wrap source consumption with try/catch or defensive operators) so Merge has nothing to aggregate.
- If you only care about the first failure, note Merge intentionally aggregates; consider alternative combinators or catch AggregateException and rethrow its first InnerException.
Example fix
// before
await foreach (var item in AsyncEnumerable.Merge(streamA, streamB)) { ... }
// after
try
{
await foreach (var item in AsyncEnumerable.Merge(
streamA.Catch((Exception e) => AsyncEnumerable.Empty<int>()),
streamB.Catch((Exception e) => AsyncEnumerable.Empty<int>()))) { ... }
}
catch (AggregateException ex)
{
foreach (var inner in ex.InnerExceptions) Log(inner);
} Defensive patterns
Strategy: try-catch
Try / catch
try { await foreach (var x in merged) ... }
catch (AggregateException agg) { foreach (var e in agg.InnerExceptions) Handle(e); } Prevention
- Wrap each source with .Catch/fallback before merging.
- Log all InnerExceptions, not just the first.
- Test source-failure paths when composing merges.
When it happens
Trigger: Calling AsyncEnumerable.Merge on multiple (or an array of) async sources where one or more sources throw during MoveNextAsync; the exception surfaces at the end of the merged enumeration after all sources have completed/cleaned up.
Common situations: Merging several event streams or message-queue subscriptions where one upstream is misconfigured (bad credentials, dropped connection, malformed data) and throws while others keep running; also occurs when a source's async enumerator throws during disposal cleanup.
Related errors
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/2ef2583847cd6304.
Report an issue: GitHub.
Appendix: source
Thrown at Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Merge.cs:174
catch (Exception ex)
{
if (errors == null)
{
errors = new List<Exception>();
}
errors.Add(ex);
}
}
// NB: If we had any errors during cleaning (and awaiting pending operations), we throw these exceptions
// instead of the original exception that may have led to running the finally block. This is similar
// to throwing from any finally block (except that we catch all exceptions to ensure cleanup of all
// concurrent sequences being merged).
if (errors != null)
{
throw new AggregateException(errors);
}
}
}
#else
{
var count = sources.Length;
var enumerators = new IAsyncEnumerator<TSource>?[count];
var moveNextTasks = new Task<bool>[count];
try
{
for (var i = 0; i < count; i++)
{
var enumerator = sources[i].GetAsyncEnumerator(cancellationToken);
enumerators[i] = enumerator;
// REVIEW: This follows the lead of the original implementation where we kick off MoveNextAsyncView on GitHub (pinned to 94b5d5ab91)