dotnet/reactive · error · ArgumentOutOfRangeException

count

Error message

count

What it means

SkipLast's count-based overload throws ArgumentOutOfRangeException("count") when count is negative. The operator buffers 'count' elements and re-emits them after the source completes, so a negative count is meaningless. Note this overload only accepts count >= 0 (unlike the observer-level variant).

Solutions

  1. Clamp the count: Math.Max(0, count) before calling SkipLast.
  2. Validate user/config input so buffer sizes cannot go negative.
  3. Skip the operator entirely when count <= 0, since SkipLast(0) just returns the source.

Example fix

// before
var res = source.SkipLast(count); // count can be negative
// after
var res = count <= 0 ? source : source.SkipLast(count);
Defensive patterns

Strategy: validation

Validate before calling

if (count < 0) throw new InvalidOperationException("SkipLast count must be >= 0");
var res = source.SkipLast(count);

Type guard

static bool IsValidCount(int n) => n >= 0;

Try / catch

try { var res = source.SkipLast(count); }
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "count") { var res = source; }

Prevention

When it happens

Trigger: Calling source.SkipLast(-1) or passing a computed/variable count that resolved to a negative number (e.g. total - received when received > total).

Common situations: Arithmetic producing a negative buffer size; user configuration allowing negative values; int subtraction in logging/truncation logic.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/SkipLast.cs:18

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT License.
// See the LICENSE file in the project root for more information. 

using System.Collections.Generic;
using System.Reactive.Concurrency;
using System.Threading.Tasks;

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<TSource> SkipLast<TSource>(this IAsyncObservable<TSource> source, int count)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (count < 0)
                throw new ArgumentOutOfRangeException(nameof(count));

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

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


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

View on GitHub (pinned to 94b5d5ab91)