{"record":{"id":"6ddbded5af421d74","repo":"dotnet/reactive","slug":"duration-skiplast","errorCode":null,"errorMessage":"duration","messagePattern":"duration","errorType":"validation","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/SkipLast.cs","lineNumber":37,"sourceCode":"\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)\n                throw new ArgumentOutOfRangeException(nameof(duration));\n\n            if (duration == TimeSpan.Zero)\n            {\n                return source;\n            }\n\n            return CreateAsyncObservable<TSource>.From(\n                source,\n                duration,\n                static (source, duration, observer) => source.SubscribeSafeAsync(AsyncObserver.SkipLast(observer, duration)));\n        }\n\n        public static IAsyncObservable<TSource> SkipLast<TSource>(this IAsyncObservable<TSource> source, TimeSpan duration, IClock clock)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n            if (duration < TimeSpan.Zero)\n                throw new ArgumentOutOfRangeException(nameof(duration));","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/SkipLast.cs#L19-L55","documentation":"The time-based SkipLast overload throws ArgumentOutOfRangeException(\"duration\") when the duration is negative (less than TimeSpan.Zero). The operator needs a non-negative window during which trailing elements are dropped. Zero is explicitly allowed and short-circuits to the source.","triggerScenarios":"Calling source.SkipLast(TimeSpan.FromSeconds(-1)) or passing a TimeSpan computed by subtraction where the subtrahend is larger (e.g. deadline - now after the deadline).","commonSituations":"Timeout math going negative; user-provided configuration accepting negative values; clock skew when durations are derived from timestamps.","solutions":["Clamp the duration: if (duration < TimeSpan.Zero) duration = TimeSpan.Zero;","Validate config/user input for non-negative durations before composing the pipeline.","Fix the arithmetic producing negative TimeSpans (clamp against now/deadline)."],"exampleFix":"// before\nvar res = source.SkipLast(deadline - clock.Now); // may be negative\n// after\nvar d = deadline - clock.Now;\nvar res = source.SkipLast(d < TimeSpan.Zero ? TimeSpan.Zero : d);","handlingStrategy":"validation","validationCode":"if (duration < TimeSpan.Zero) duration = TimeSpan.Zero;\nvar res = source.SkipLast(duration);","typeGuard":"static bool IsValidDuration(TimeSpan d) => d >= TimeSpan.Zero;","tryCatchPattern":"try { var res = source.SkipLast(duration); }\ncatch (ArgumentOutOfRangeException ex) when (ex.ParamName == \"duration\") { var res = source; }","preventionTips":["Clamp deadline-based durations against TimeSpan.Zero.","Validate configured durations are non-negative at load time.","Be careful with TimeSpan arithmetic around deadlines/clock skew."],"tags":["argument-out-of-range","timespan","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"}