dotnet/reactive · error · ObjectDisposedException
Cannot access a disposed object. Object name: ''.
Error message
Cannot access a disposed object. Object name: ''.
What it means
MemoizedBuffer.GetEnumerator checks the buffer's _disposed flag and throws ObjectDisposedException once Dispose() has been called on the buffer. After disposal, new enumerators can no longer be handed out, so requesting one throws "Cannot access a disposed object".
Solutions
- Keep the buffer alive (dispose it) only after all consumers have finished enumerating.
- Obtain all enumerators inside the lifetime of the buffer's using block.
- If lazy consumption is needed, materialize with ToList/ToArray before disposing.
Example fix
// before
IBuffer<int> buffer;
using (buffer = source.Memoize()) { }
foreach (var x in buffer) { } // throws
// after
using (var buffer = source.Memoize())
{
foreach (var x in buffer) { }
} Defensive patterns
Strategy: try-catch
Validate before calling
bool usable = buffer is IBuffer<T> b && !IsDisposed(b); // track disposal via your own flag since _disposed is private
if (!usable) { /* re-memoize or fail fast */ } Type guard
static bool CanEnumerate<T>(IBuffer<T> buffer, HashSet<object> disposed) => !disposed.Contains(buffer);
Try / catch
try { foreach (var x in buffer) Process(x); }
catch (ObjectDisposedException) { buffer = source.Memoize(); foreach (var x in buffer) Process(x); } Prevention
- Scope buffer disposal so it encloses all enumeration
- Never cache an IBuffer beyond its using block
- Materialize with ToList/ToArray before disposal if late reads are needed
When it happens
Trigger: Calling GetEnumerator() on the IBuffer returned by Memoize after the buffer (or all of its leases) has been disposed — e.g. enumerating the buffer after a using block over the buffer ended, or after the owning scope disposed it.
Common situations: Storing the IBuffer in a field or cache while disposing it in a using statement; concurrent consumers starting enumeration after the producer disposed the buffer; returning the buffer from a method that disposes it before the caller enumerates.
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
- Specified argument was out of the range of valid values…
- Value cannot be null. (Parameter 'source')
- Value cannot be null. (Parameter 'source')
- Value cannot be null. (Parameter 'source')
- Specified argument was out of the range of valid values…
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/0bab97fd58190bf2.
Report an issue: GitHub.
Appendix: source
Thrown at Ix.NET/Source/System.Interactive/System/Linq/Operators/Memoize.cs:143
: this(source, new MaxRefCountList<T>())
{
}
public MemoizedBuffer(IEnumerator<T> source, int readerCount)
: this(source, new RefCountList<T>(readerCount))
{
}
private MemoizedBuffer(IEnumerator<T> source, IRefCountList<T> buffer)
{
_source = source;
_buffer = buffer;
}
public IEnumerator<T> GetEnumerator()
{
if (_disposed)
throw new ObjectDisposedException("");
return GetEnumerator_();
}
IEnumerator IEnumerable.GetEnumerator()
{
if (_disposed)
throw new ObjectDisposedException("");
return GetEnumerator();
}
public void Dispose()
{
lock (_gate)
{
if (!_disposed)
{View on GitHub (pinned to 94b5d5ab91)