dotnet/reactive · error · ArgumentOutOfRangeException

throw new ArgumentOutOfRangeException(nameof(retryCount));

Error message

throw new ArgumentOutOfRangeException(nameof(retryCount));

What it means

The Retry(source, retryCount) overload validates retryCount and throws ArgumentOutOfRangeException when it is negative. retryCount bounds the number of re-subscription attempts; a negative count is meaningless so the guard rejects it (after the source null check).

Solutions

  1. Use Retry(source) without a count for infinite retries, or pass a non-negative count.
  2. Clamp: retryCount = Math.Max(0, attempts).
  3. Validate maxRetries at config load, rejecting negatives with a clear message.

Example fix

// before
var retried = AsyncObservable.Retry(source, retryCount: -1); // -1 meant 'infinite'
// after
var retried = AsyncObservable.Retry(source); // infinite retries
Defensive patterns

Strategy: validation

Validate before calling

if (retryCount < 0) throw new ArgumentException("retryCount must be >= 0", nameof(retryCount));

Try / catch

try { var retried = AsyncObservable.Retry(source, retryCount); } catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "retryCount") { /* use parameterless Retry for infinite retries */ }

Prevention

When it happens

Trigger: Calling AsyncObservable.Retry(source, retryCount) with retryCount < 0, e.g. a configured attempts value of -1 intended as 'retry forever', or a computed remaining-attempts counter that went negative.

Common situations: Using -1 for 'infinite retries' (a convention from other libraries); config values like maxRetries=-1; decrementing a counter below zero before passing it in.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Retry.cs:34

            return Create(
                source,
                async static (source, observer) =>
                {
                    var (sink, inner) = AsyncObserver.Retry(observer, source);

                    var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);

                    return StableCompositeAsyncDisposable.Create(subscription, inner);
                });
        }

        public static IAsyncObservable<TSource> Retry<TSource>(this IAsyncObservable<TSource> source, int retryCount)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (retryCount < 0)
                throw new ArgumentOutOfRangeException(nameof(retryCount));

            return CreateAsyncObservable<TSource>.From(
                source,
                retryCount,
                static async (source, retryCount, observer) =>
                {
                    var (sink, inner) = AsyncObserver.Retry(observer, source, retryCount);

                    var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);

                    return StableCompositeAsyncDisposable.Create(subscription, inner);
                });
        }
    }

    public partial class AsyncObserver
    {
        public static (IAsyncObserver<TSource>, IAsyncDisposable) Retry<TSource>(IAsyncObserver<TSource> observer, IAsyncObservable<TSource> source)

View on GitHub (pinned to 94b5d5ab91)