{"record":{"id":"dfc5f2d8cdc422a2","repo":"dotnet/reactive","slug":"count-skiplast","errorCode":null,"errorMessage":"count","messagePattern":"count","errorType":"validation","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/SkipLast.cs","lineNumber":18,"sourceCode":"﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT License.\n// See the LICENSE file in the project root for more information. \n\nusing System.Collections.Generic;\nusing System.Reactive.Concurrency;\nusing System.Threading.Tasks;\n\nnamespace System.Reactive.Linq\n{\n    public partial class AsyncObservable\n    {\n        public static IAsyncObservable<TSource> SkipLast<TSource>(this IAsyncObservable<TSource> source, int count)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n            if (count < 0)\n                throw new ArgumentOutOfRangeException(nameof(count));\n\n            if (count == 0)\n            {\n                return source;\n            }\n\n            return CreateAsyncObservable<TSource>.From(\n                source,\n                count,\n                static (source, count, observer) => source.SubscribeSafeAsync(AsyncObserver.SkipLast(observer, count)));\n        }\n\n\n        public static IAsyncObservable<TSource> SkipLast<TSource>(this IAsyncObservable<TSource> source, TimeSpan duration)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n            if (duration < TimeSpan.Zero)","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/SkipLast.cs#L1-L36","documentation":"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).","triggerScenarios":"Calling source.SkipLast(-1) or passing a computed/variable count that resolved to a negative number (e.g. total - received when received > total).","commonSituations":"Arithmetic producing a negative buffer size; user configuration allowing negative values; int subtraction in logging/truncation logic.","solutions":["Clamp the count: Math.Max(0, count) before calling SkipLast.","Validate user/config input so buffer sizes cannot go negative.","Skip the operator entirely when count <= 0, since SkipLast(0) just returns the source."],"exampleFix":"// before\nvar res = source.SkipLast(count); // count can be negative\n// after\nvar res = count <= 0 ? source : source.SkipLast(count);","handlingStrategy":"validation","validationCode":"if (count < 0) throw new InvalidOperationException(\"SkipLast count must be >= 0\");\nvar res = source.SkipLast(count);","typeGuard":"static bool IsValidCount(int n) => n >= 0;","tryCatchPattern":"try { var res = source.SkipLast(count); }\ncatch (ArgumentOutOfRangeException ex) when (ex.ParamName == \"count\") { var res = source; }","preventionTips":["Clamp computed counts with Math.Max(0, count).","Validate user/config-provided buffer sizes as non-negative.","Remember count == 0 is a valid no-op at this level."],"tags":["argument-out-of-range","count","async-rx"],"backgroundTag":"argument-out-of-range","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}