dotnet/reactive · error · ArgumentOutOfRangeException

duration

Error message

duration

What it means

The TimeSpan overload Skip(source, duration) throws ArgumentOutOfRangeException with paramName "duration" when a negative TimeSpan is passed. A negative skip duration is meaningless, so the library rejects it eagerly.

Solutions

  1. Ensure the duration is non-negative before calling Skip
  2. Clamp with a max against TimeSpan.Zero when the value is computed (e.g. remaining time)
  3. Fix the duration computation (use a monotonic clock or clamp at the source)

Example fix

// before
var remaining = deadline - DateTime.UtcNow;
source.Skip(remaining); // throws if deadline passed
// after
var remaining = deadline - DateTime.UtcNow;
if (remaining > TimeSpan.Zero)
    source.Skip(remaining);
Defensive patterns

Strategy: validation

Validate before calling

if (duration < TimeSpan.Zero) duration = TimeSpan.Zero;
var res = source.Skip(duration);

Try / catch

try { var res = source.Skip(duration); }
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "duration") { /* clamp and retry */ }

Prevention

When it happens

Trigger: Calling Skip(source, TimeSpan) with a negative value, e.g. computed as deadline - now where now has passed the deadline, or from misparsed/converted time values.

Common situations: Computing remaining time from a deadline that already elapsed; clock skew or DateTime.UtcNow vs local time mixups; parsing durations with a sign from configuration.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Skip.cs:37

                throw new ArgumentOutOfRangeException(nameof(count));

            if (count == 0)
            {
                return source;
            }

            return CreateAsyncObservable<TSource>.From(
                source,
                count,
                static (source, count, observer) => source.SubscribeSafeAsync(AsyncObserver.Skip(observer, count)));
        }

        public static IAsyncObservable<TSource> Skip<TSource>(this IAsyncObservable<TSource> source, TimeSpan duration)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (duration < TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(duration));

            if (duration == TimeSpan.Zero)
            {
                return source;
            }

            // REVIEW: May be easier to just use SkipUntil with a Timer parameter. Do we want Skip on the observer?

            return CreateAsyncObservable<TSource>.From(
                source,
                duration,
                static async (source, duration, observer) =>
                {
                    var (sourceObserver, timer) = await AsyncObserver.Skip(observer, duration).ConfigureAwait(false);

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

                    return StableCompositeAsyncDisposable.Create(subscription, timer);

View on GitHub (pinned to 94b5d5ab91)