{"record":{"id":"8b64dfc8c29de6ca","repo":"dotnet/reactive","slug":"keyselector-observable-aggregates","errorCode":null,"errorMessage":"keySelector","messagePattern":"keySelector","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Linq/Observable.Aggregates.cs","lineNumber":1556,"sourceCode":"        /// Returns the elements in an observable sequence with the maximum key value.\n        /// </summary>\n        /// <typeparam name=\"TSource\">The type of the elements in the source sequence.</typeparam>\n        /// <typeparam name=\"TKey\">The type of the key computed for each element in the source sequence.</typeparam>\n        /// <param name=\"source\">An observable sequence to get the maximum elements for.</param>\n        /// <param name=\"keySelector\">Key selector function.</param>\n        /// <returns>An observable sequence containing a list of zero or more elements that have a maximum key value.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"source\"/> or <paramref name=\"keySelector\"/> is null.</exception>\n        /// <remarks>The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.</remarks>\n        public static IObservable<IList<TSource>> MaxBy<TSource, TKey>(this IObservable<TSource> source, Func<TSource, TKey> keySelector)\n        {\n            if (source == null)\n            {\n                throw new ArgumentNullException(nameof(source));\n            }\n\n            if (keySelector == null)\n            {\n                throw new ArgumentNullException(nameof(keySelector));\n            }\n\n            return s_impl.MaxBy(source, keySelector);\n        }\n\n        /// <summary>\n        /// Returns the elements in an observable sequence with the maximum key value according to the specified comparer.\n        /// </summary>\n        /// <typeparam name=\"TSource\">The type of the elements in the source sequence.</typeparam>\n        /// <typeparam name=\"TKey\">The type of the key computed for each element in the source sequence.</typeparam>\n        /// <param name=\"source\">An observable sequence to get the maximum elements for.</param>\n        /// <param name=\"keySelector\">Key selector function.</param>\n        /// <param name=\"comparer\">Comparer used to compare key values.</param>\n        /// <returns>An observable sequence containing a list of zero or more elements that have a maximum key value.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"source\"/> or <paramref name=\"keySelector\"/> or <paramref name=\"comparer\"/> is null.</exception>\n        /// <remarks>The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.</remarks>\n        public static IObservable<IList<TSource>> MaxBy<TSource, TKey>(this IObservable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)\n        {","sourceCodeStart":1538,"sourceCodeEnd":1574,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Linq/Observable.Aggregates.cs#L1538-L1574","documentation":"Observable.MaxBy throws ArgumentNullException when the keySelector delegate passed to it is null. Rx operators validate all arguments eagerly at call time, before returning the observable, so the exception is thrown synchronously rather than surfaced through the subscription. keySelector is required because MaxBy must compute a comparison key for each element to find the maximum elements.","triggerScenarios":"Calling Observable.MaxBy(source, null) — the two-argument overload (IObservable<TSource>, Func<TSource,TKey>) at Observable.Aggregates.cs:1556 with a null second argument, e.g. MaxBy(x => someSelector) where someSelector is an uninitialized field or a failed lookup.","commonSituations":"Storing the key selector in a field or dictionary that was never initialized; dynamically resolving the selector from config/dependency injection and getting null; refactoring code so the lambda was replaced by a nullable delegate variable.","solutions":["Pass a valid non-null lambda or method group as keySelector, e.g. source.MaxBy(x => x.Priority).","If the selector comes from a variable, check it for null before calling MaxBy and throw a descriptive error or substitute a default selector.","Fix the initialization of the field/property/config value that supplies the selector so it is never null."],"exampleFix":"// before\nFunc<Order, int> selector = config?.OrderSelector;\nvar max = orders.MaxBy(selector); // NRE/ArgumentNullException if config is null\n// after\nvar max = orders.MaxBy(o => o.Total); // or: orders.MaxBy(selector ?? (o => o.Total))","handlingStrategy":"validation","validationCode":"if (source == null) throw new ArgumentNullException(nameof(source));\nif (keySelector == null) throw new ArgumentNullException(nameof(keySelector));\nvar max = source.MaxBy(keySelector);","typeGuard":"bool HasSelector<T, TKey>(Func<T, TKey> selector) => selector is not null;","tryCatchPattern":"try { var max = source.MaxBy(keySelector); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"keySelector\") { /* supply default selector or log */ }","preventionTips":["Never store key selectors in nullable fields; pass lambdas directly at the call site.","When resolving selectors dynamically, fail fast with a clear error at resolution time.","Enable nullable reference types (LangVersion 8+ #nullable enable) so nullable delegates surface at compile time."],"tags":["csharp","rx","argument-validation","null-reference"],"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"}