dotnet/reactive · error · InvalidOperationException
Exception of type 'System.InvalidOperationException' was…
Error message
Exception of type 'System.InvalidOperationException' was thrown.
What it means
AsyncEnumerable.Never never produces values or completes; its enumerator's Current getter is defined to throw InvalidOperationException because accessing Current without a produced element is meaningless for this operator. This is an internal-invariant guard: there is no current element by design.
Solutions
- Never read Current unless MoveNextAsync returned true; for Never it never will, so treat the stream as permanently silent.
- Replace Never with a source that actually emits (e.g. AsyncEnumerable.Return) if you expected values.
- If you need an abortable silent stream, await a Task that never completes honoring the token, or use Timer-based sources instead.
Example fix
// before
var e = AsyncEnumerable.Never<int>().GetAsyncEnumerator();
var x = e.Current; // throws
// after
if (await e.MoveNextAsync()) { var x = e.Current; } // never true for Never
Defensive patterns
Strategy: validation
Validate before calling
if (await enumerator.MoveNextAsync()) { use(enumerator.Current); } // never true for Never Type guard
bool HasCurrent(IAsyncEnumerator<T> e) => e.MoveNextAsync().AsTask().GetAwaiter().GetResult();
Try / catch
try { var v = e.Current; }
catch (InvalidOperationException) { /* Never yields: treat as no-value */ } Prevention
- Only access Current after a successful MoveNextAsync.
- Never expect values from AsyncEnumerable.Never — use it purely as a placeholder/park.
- In tests, assert the sequence never emits instead of reading Current.
When it happens
Trigger: Accessing enumerator.Current (directly or via foreach/state machine misuse) on an AsyncEnumerable.Never<TValue> enumerator — e.g. manually calling MoveNextAsync logic bypassed, or a consumer framework reading Current without a successful MoveNextAsync.
Common situations: Using Never in tests or placeholder pipelines and accidentally reading Current; combining Never with operators that assume at least one element; incorrect manual enumerator loops that don't check MoveNextAsync's result.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Disposable already assigned.
- Value cannot be null. (Parameter 'handlers')
- Value cannot be null. (Parameter 'handlers')
- Could not find static event
- Could not find instance event
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/5a5a1b34392fddee.
Report an issue: GitHub.
Appendix: source
Thrown at Ix.NET/Source/System.Interactive.Async/System/Linq/Operators/Never.cs:38
private sealed class NeverAsyncEnumerable<TValue> : IAsyncEnumerable<TValue>
{
internal static readonly NeverAsyncEnumerable<TValue> Instance = new();
public IAsyncEnumerator<TValue> GetAsyncEnumerator(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested(); // NB: [LDM-2018-11-28] Equivalent to async iterator behavior.
return new NeverAsyncEnumerator(cancellationToken);
}
private sealed class NeverAsyncEnumerator(CancellationToken token) : IAsyncEnumerator<TValue>
{
private readonly CancellationToken _token = token;
private CancellationTokenRegistration _registration;
private bool _once;
public TValue Current => throw new InvalidOperationException();
public ValueTask DisposeAsync()
{
_registration.Dispose();
return default;
}
public ValueTask<bool> MoveNextAsync()
{
if (_once)
{
return new ValueTask<bool>(false);
}
_once = true;
var task = new TaskCompletionSource<bool>();
_registration = _token.Register(state => ((TaskCompletionSource<bool>)state!).TrySetCanceled(_token), task);
return new ValueTask<bool>(task.Task);View on GitHub (pinned to 94b5d5ab91)