dotnet/reactive · error · NotSupportedException
AnonymousAsyncIterator cannot be cloned. It is only…
Error message
AnonymousAsyncIterator cannot be cloned. It is only intended for use as an iterator.
What it means
AnonymousAsyncIterator is the iterator created by async LINQ operators built from lambdas/delegates; it captures compiler-generated state that cannot be duplicated. Its Clone() override therefore throws NotSupportedException stating it can only be used as an iterator. Cloning is normally an internal detail of AsyncIteratorBase used for concurrent/multiple enumeration.
Solutions
- Create a new enumeration per consumer: call the operator again (each call returns a fresh IAsyncEnumerable/iterator).
- Serialize access: enumerate sequentially or buffer results before sharing.
- If multiple independent streams are needed, materialize with ToListAsync and enumerate the list in parallel.
Example fix
// before var src = AsyncEnumerable.Range(0, 10).Select(async x => x * 2); await Task.WhenAll(Consume(src.GetEnumerator()), Consume(src.GetEnumerator())); // clones iterator // after var src = AsyncEnumerable.Range(0, 10).Select(x => x * 2); await Task.WhenAll(Consume(src), Consume(src)); // fresh enumerator per call
Defensive patterns
Strategy: fallback
Validate before calling
// request a fresh enumerable per consumer instead of cloning iterators: each call to the operator returns an independent IAsyncEnumerable.
Try / catch
try { consume(it.Clone()); } catch (NotSupportedException ex) when (ex.Message.Contains("cannot be cloned")) { consume(source.GetEnumerator()); } Prevention
- Never share a single iterator/enumerator across concurrent consumers.
- Call the composing operator again for each independent stream.
- Materialize with ToListAsync before parallel consumption.
- Avoid deriving custom operators from AnonymousAsyncIterator if multi-enumeration is required.
When it happens
Trigger: Enumerating (or re-enumerating concurrently) an async operator result whose iterator is an AnonymousAsyncIterator in a path that calls Clone(), such as multiple simultaneous MoveNextAsync consumers or code that explicitly clones the iterator.
Common situations: Sharing one IAsyncEnumerable across parallel consumers expecting independent iterators, calling GetEnumerator/Clone directly, or custom operators deriving from AnonymousAsyncIterator and being enumerated more than once concurrently.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/644e00a292df9b6f.
Report an issue: GitHub.
Appendix: source
Thrown at Ix.NET/Source/System.Linq.Async/System/Linq/AsyncEnumerator.cs:79
private sealed class AnonymousAsyncIterator<T> : AsyncIterator<T>
{
private readonly Func<T> _currentFunc;
private readonly Func<ValueTask<bool>> _moveNext;
private Func<ValueTask>? _dispose;
public AnonymousAsyncIterator(Func<ValueTask<bool>> moveNext, Func<T> currentFunc, Func<ValueTask> dispose)
{
_moveNext = moveNext;
_currentFunc = currentFunc;
_dispose = dispose;
// Explicit call to initialize enumerator mode
GetAsyncEnumerator(default);
}
public override AsyncIteratorBase<T> Clone()
{
throw new NotSupportedException("AnonymousAsyncIterator cannot be cloned. It is only intended for use as an iterator.");
}
public override async ValueTask DisposeAsync()
{
var dispose = Interlocked.Exchange(ref _dispose, null);
if (dispose != null)
{
await dispose().ConfigureAwait(false);
}
await base.DisposeAsync().ConfigureAwait(false);
}
protected override async ValueTask<bool> MoveNextCore()
{
switch (_state)
{View on GitHub (pinned to 94b5d5ab91)