{"record":{"id":"382e7caa218f8cf1","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-comparer-observable","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'comparer')","messagePattern":"Value cannot be null\\. \\(Parameter 'comparer'\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Linq/Observable.Aggregates.cs","lineNumber":1587,"sourceCode":"        /// <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        {\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            if (comparer == null)\n            {\n                throw new ArgumentNullException(nameof(comparer));\n            }\n\n            return s_impl.MaxBy(source, keySelector, comparer);\n        }\n\n        #endregion\n\n        #region + Min +\n\n        /// <summary>\n        /// Returns the minimum element in an observable sequence.\n        /// </summary>\n        /// <typeparam name=\"TSource\">The type of the elements in the source sequence.</typeparam>\n        /// <param name=\"source\">An observable sequence to determine the minimum element of.</param>\n        /// <returns>An observable sequence containing a single element with the minimum element in the source sequence.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"source\"/> 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<TSource> Min<TSource>(this IObservable<TSource> source)","sourceCodeStart":1569,"sourceCodeEnd":1605,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Linq/Observable.Aggregates.cs#L1569-L1605","documentation":"The comparer overload of Observable.MaxBy throws ArgumentNullException when the IComparer<TKey> comparer argument is null. The comparer is mandatory in this overload because it replaces the default Comparer<TKey>.Default used by the two-argument overload; without it no ordering can be established.","triggerScenarios":"Calling Observable.MaxBy(source, keySelector, null) at Observable.Aggregates.cs:1587 with a null third argument, e.g. a comparer resolved from configuration or a service that returned null.","commonSituations":"A custom IComparer<T> instance held in a nullable field never assigned; a factory method returning null when comparison rules are unconfigured; switching from the two-argument to the three-argument overload and passing null intending 'default comparer'.","solutions":["Pass a valid comparer, e.g. Comparer<TKey>.Default if you actually want default semantics, or a custom Comparer<TKey>.Create(...).","Use the two-argument MaxBy overload if you do not need a custom comparer.","Null-check the comparer before the call and fall back to Comparer<TKey>.Default."],"exampleFix":"// before\nobs.MaxBy(x => x.Name, config.Comparer); // Comparer property is null\n// after\nobs.MaxBy(x => x.Name, config.Comparer ?? Comparer<string>.Default);","handlingStrategy":"validation","validationCode":"var cmp = comparer ?? Comparer<TKey>.Default;\nvar r = source.MaxBy(keySelector, cmp);","typeGuard":"bool HasComparer<TKey>(IComparer<TKey> c) => c is not null;","tryCatchPattern":"try { var r = source.MaxBy(sel, cmp); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"comparer\") { var r = source.MaxBy(sel); }","preventionTips":["Use the two-argument MaxBy overload when you want default comparison semantics instead of passing null.","Default uninitialized comparer fields to Comparer<T>.Default.","Ensure comparer factories/registrations never return null; throw at configuration load time."],"tags":["csharp","rx","argument-validation","null-reference","icomparer"],"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"}