{"record":{"id":"8c1574038a679027","repo":"dotnet/reactive","slug":"argumentnullexception-timeinterval","errorCode":null,"errorMessage":"ArgumentNullException","messagePattern":"ArgumentNullException","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/TimeInterval.cs","lineNumber":48,"sourceCode":"        }\n    }\n\n    public partial class AsyncObserver\n    {\n        public static IAsyncObserver<TSource> TimeInterval<TSource>(IAsyncObserver<TimeInterval<TSource>> observer)\n        {\n            if (observer == null)\n                throw new ArgumentNullException(nameof(observer));\n\n            return TimeInterval(observer, Clock.Default);\n        }\n\n        public static IAsyncObserver<TSource> TimeInterval<TSource>(IAsyncObserver<TimeInterval<TSource>> observer, IClock clock)\n        {\n            if (observer == null)\n                throw new ArgumentNullException(nameof(observer));\n            if (clock == null)\n                throw new ArgumentNullException(nameof(clock));\n\n            var last = clock.Now;\n\n            return Select<TSource, TimeInterval<TSource>>(observer, x =>\n            {\n                var now = clock.Now;\n                var interval = now - last;\n                last = now;\n\n                return new TimeInterval<TSource>(x, interval);\n            });\n        }\n    }\n}\n","sourceCodeStart":30,"sourceCodeEnd":63,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/TimeInterval.cs#L30-L63","documentation":"In the same clock-taking AsyncObserver.TimeInterval overload, a null IClock is rejected because the implementation reads clock.Now both to seed `last` and to compute each interval. Without a clock the operator cannot measure time, so ArgumentNullException is thrown before any subscription work. The exception is raised from the same public method, only from the clock check.","triggerScenarios":"Calling AsyncObserver.TimeInterval<TSource>(observer, clock) with clock == null; parameterless overload users are unaffected since it substitutes Clock.Default.","commonSituations":"DI/config-resolved IClock not registered; test code passing a mock clock variable left null; swapping time sources during migration to System.TimeProvider-like abstractions.","solutions":["Pass a valid clock such as Clock.Default, Clock.Virtual/TestClock, or a mock","Use AsyncObserver.TimeInterval(observer) which defaults to Clock.Default","Fix the null-producing clock resolution"],"exampleFix":"// before\nvar obs = AsyncObserver.TimeInterval<int>(observer, clock); // clock null\n// after\nvar obs = AsyncObserver.TimeInterval<int>(observer, clock ?? Clock.Default);","handlingStrategy":"validation","validationCode":"if (clock is null) clock = Clock.Default;\nvar obs = AsyncObserver.TimeInterval<int>(observer, clock);","typeGuard":"bool IsValidClock(IClock? c) => c is not null;","tryCatchPattern":"try\n{\n    obs = AsyncObserver.TimeInterval<int>(observer, clock);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"clock\")\n{\n    obs = AsyncObserver.TimeInterval<int>(observer); // uses Clock.Default\n}","preventionTips":["Register/resolve IClock defensively with Clock.Default fallback","Coalesce null clocks at the call site","Use the single-argument overload when custom timing is not needed"],"tags":["argument-null","clock","validation"],"backgroundTag":"null-argument","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"}