dotnet/reactive · error · OverflowException

RefCountDisposable can't handle more than 2147483647…

Error message

RefCountDisposable can't handle more than 2147483647 disposables

What it means

RefCountDisposable packs an active-child counter into bits 0..30 of an int (bit 31 is the disposed flag), so it can hand out at most int.MaxValue inner disposables. GetDisposable throws OverflowException when 2147483647 inner disposables are already outstanding.

Solutions

  1. Dispose inner disposables returned by GetDisposable as soon as they are no longer needed.
  2. Track outstanding leases with a bounded cap or semaphore to prevent runaway acquisition.
  3. If legitimately unbounded, replace with a custom counting scheme using a long counter or SplitDispose-free design.

Example fix

// before
while (running) leases.Add(refCount.GetDisposable()); // never released
// after
while (running)
{
    var d = refCount.GetDisposable();
    try { /* work */ }
    finally { d.Dispose(); }
}
Defensive patterns

Strategy: validation

Validate before calling

// Cap outstanding leases
if (Interlocked.Increment(ref outstanding) > MaxLeases)
    throw new InvalidOperationException("Too many outstanding inner disposables");
var d = refCount.GetDisposable();

Try / catch

try { var d = refCount.GetDisposable(); }
catch (OverflowException) { /* back off, force disposal of outstanding leases */ }

Prevention

When it happens

Trigger: Calling GetDisposable() 2,147,483,648 times on a single RefCountDisposable without any of the returned inner disposables being disposed — usually only via a stress/leak loop.

Common situations: Unbounded subscription/lease creation in a hot loop where inner disposables are never disposed, effectively a leak that exhausts the 31-bit counter; extremely rare outside synthetic benchmarks.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/e96d2b23ee515ad1. Report an issue: GitHub.

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Disposables/RefCountDisposable.cs:78

            var cnt = Volatile.Read(ref _count);

            for (; ; )
            {
                // If bit 31 is set and the active count is zero, don't create an inner
                if (cnt == int.MinValue)
                {
                    if (_throwWhenDisposed)
                    {
                        throw new ObjectDisposedException("RefCountDisposable");
                    }

                    return Disposable.Empty;
                }

                // Should not overflow the bits 0..30
                if ((cnt & 0x7FFFFFFF) == int.MaxValue)
                {
                    throw new OverflowException($"RefCountDisposable can't handle more than {int.MaxValue} disposables");
                }

                // Increment the active count by one, works because the increment
                // won't affect bit 31
                var u = Interlocked.CompareExchange(ref _count, cnt + 1, cnt);
                if (u == cnt)
                {
                    return new InnerDisposable(this);
                }
                cnt = u;
            }
        }

        /// <summary>
        /// Disposes the underlying disposable only when all dependent disposables have been disposed.
        /// </summary>
        public void Dispose()
        {

View on GitHub (pinned to 94b5d5ab91)