dotnet/reactive · error · ObjectDisposedException
Cannot access a disposed object.
Error message
Cannot access a disposed object.
What it means
PushPullAdapter.MoveNext() throws ObjectDisposedException once the adapter has been disposed. The adapter backs legacy IEnumerable-based observable bridges; iterating (MoveNext) after Dispose is treated as a bug because the underlying enumerator/subscription is already torn down.
Solutions
- Stop enumerating once the subscription/adapter is disposed; dispose the enumerator inside a using block and do not reuse it.
- Check for completion before continuing: when current notification is OnError/OnCompleted, stop calling MoveNext.
- Guard concurrent access with a lock, or serialize dispose/enumerate on one thread.
Example fix
// before
var en = adapter.GetEnumerator();
adapter.Dispose();
en.MoveNext();
// after
using (var en = adapter.GetEnumerator())
{
while (en.MoveNext()) { /* ... */ }
} // disposed after enumeration ends Defensive patterns
Strategy: try-catch
Validate before calling
if (disposed) return; // track disposal state before enumerating
Type guard
static bool CanMoveNext(PushPullAdapter a) => !a.IsDisposed; // expose/track via wrapper
Try / catch
try { en.MoveNext(); } catch (ObjectDisposedException) { /* enumeration already ended */ } Prevention
- Wrap enumerator usage in using blocks and never use the enumerator after dispose.
- Stop calling MoveNext after an OnError/OnCompleted notification.
- Avoid sharing one adapter/enumerator across threads.
When it happens
Trigger: Calling MoveNext() on the adapter's enumerator after Dispose() was called — e.g. continuing to enumerate after the observable completed and was disposed, or enumerating a disposed subscription's adapter.
Common situations: Holding an IEnumerator across a dispose (using-block exited early), multi-threaded consumption where one thread disposes while another calls MoveNext, legacy code paths still using the #if-compiled PushPullAdapter.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- EventLoopScheduler
- RefCountDisposable
- Cannot access a disposed object. Object name: ''.
- Cannot access a disposed object. Object name: ''.
- Strings_Core.OBSERVER_TERMINATED
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/278c8b3a0ba455c4.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Internal/PushPullAdapter.cs:62
{
get { return current.Value; }
}
public void Dispose()
{
disposed = true;
dispose();
}
object System.Collections.IEnumerator.Current
{
get { return this.Current; }
}
public bool MoveNext()
{
if (disposed)
throw new ObjectDisposedException("");
if (!done)
{
current = moveNext();
done = current.Kind != NotificationKind.OnNext;
}
current.Exception?.Throw();
return current.HasValue;
}
public void Reset()
{
throw new NotSupportedException();
}
}
}View on GitHub (pinned to 94b5d5ab91)