dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'skip')

Error message

Value cannot be null. (Parameter 'skip')

What it means

Buffer<TSource>(source, count, skip) throws ArgumentNullException(nameof(skip)) when skip <= 0. The skip value controls how far the buffer window advances between buffers; a non-positive skip would stall or corrupt windowing, so it is rejected. The library reports it as ArgumentNullException with parameter 'skip' even though it is semantically a range error.

Solutions

  1. Pass skip >= 1; clamp: skip = Math.Max(1, skip).
  2. If you wanted non-overlapping buffers, pass skip equal to count, not 0 (source.Buffer(count, count)).
  3. Validate overlap/skip configuration before composing the pipeline and reject <= 0 with a domain error.

Example fix

// before
var sliding = source.Buffer(10, overlap); // overlap == 10 -> skip == 0
// after
var skip = count - overlap;
if (skip <= 0) throw new ArgumentException("overlap must be smaller than count");
var sliding = source.Buffer(count, skip);
Defensive patterns

Strategy: validation

Validate before calling

var skip = count - overlap;
if (skip <= 0) throw new ArgumentException("overlap must be smaller than count so skip >= 1", nameof(overlap));

Type guard

bool IsValidSkip(int skip) => skip > 0;

Try / catch

try { var sliding = source.Buffer(count, skip); }
catch (ArgumentNullException ex) when (ex.ParamName == "skip") { throw new InvalidOperationException("skip must be >= 1; use skip == count for non-overlapping buffers", ex); }

Prevention

When it happens

Trigger: Calling source.Buffer(count, 0) or source.Buffer(count, negative); skip computed from config or arithmetic (e.g. count - overlap where overlap >= count); accidentally passing 0 because 'no skip' seemed like 0 instead of skip == count.

Common situations: Implementing sliding windows where overlap is configurable — overlap == count makes skip 0; UI or API inputs accepting 0 for 'no advance'; uninitialized int fields.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Buffer.cs:35

            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (count <= 0)
                throw new ArgumentNullException(nameof(count));

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

        public static IAsyncObservable<IList<TSource>> Buffer<TSource>(this IAsyncObservable<TSource> source, int count, int skip)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (count <= 0)
                throw new ArgumentNullException(nameof(count));
            if (skip <= 0)
                throw new ArgumentNullException(nameof(skip));

            return CreateAsyncObservable<IList<TSource>>.From(
                source,
                (count, skip),
                static (source, state, observer) => source.SubscribeSafeAsync(AsyncObserver.Buffer(observer, state.count, state.skip)));
        }

        public static IAsyncObservable<IList<TSource>> Buffer<TSource>(this IAsyncObservable<TSource> source, TimeSpan timeSpan)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (timeSpan < TimeSpan.Zero)
                throw new ArgumentNullException(nameof(timeSpan));

            return CreateAsyncObservable<IList<TSource>>.From(
                source,
                timeSpan,
                static async (source, timeSpan, observer) =>

View on GitHub (pinned to 94b5d5ab91)