{"record":{"id":"347e088a86aa8c45","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-keyselector-347e08","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'keySelector')","messagePattern":"Value cannot be null\\. \\(Parameter 'keySelector'\\)","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Ix.NET/Source/System.Interactive/System/Linq/Operators/DistinctUntilChanged.cs","lineNumber":55,"sourceCode":"                throw new ArgumentNullException(nameof(comparer));\n\n            return DistinctUntilChangedCore(source, x => x, comparer);\n        }\n\n        /// <summary>\n        /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values.\n        /// </summary>\n        /// <typeparam name=\"TSource\">Source sequence element type.</typeparam>\n        /// <typeparam name=\"TKey\">Key type.</typeparam>\n        /// <param name=\"source\">Source sequence.</param>\n        /// <param name=\"keySelector\">Key selector.</param>\n        /// <returns>Sequence without adjacent non-distinct elements.</returns>\n        public static IEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n            if (keySelector == null)\n                throw new ArgumentNullException(nameof(keySelector));\n\n            return DistinctUntilChangedCore(source, keySelector, EqualityComparer<TKey>.Default);\n        }\n\n        /// <summary>\n        /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values.\n        /// </summary>\n        /// <typeparam name=\"TSource\">Source sequence element type.</typeparam>\n        /// <typeparam name=\"TKey\">Key type.</typeparam>\n        /// <param name=\"source\">Source sequence.</param>\n        /// <param name=\"keySelector\">Key selector.</param>\n        /// <param name=\"comparer\">Comparer used to compare key values.</param>\n        /// <returns>Sequence without adjacent non-distinct elements.</returns>\n        public static IEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n            if (keySelector == null)","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Ix.NET/Source/System.Interactive/System/Linq/Operators/DistinctUntilChanged.cs#L37-L73","documentation":"The DistinctUntilChanged(source, keySelector) overload requires a non-null Func<TSource,TKey> used to compute comparison keys, and throws ArgumentNullException for a null keySelector. Validation is eager: the exception is thrown when the operator method is invoked, before any element is processed. This prevents a NullReferenceException deep inside the enumeration.","triggerScenarios":"Calling DistinctUntilChanged(source, keySelector) where the keySelector lambda/expression reference is null — most often when it is stored in a variable, field, or passed as a method parameter that was null, or a lookup of delegates returns null.","commonSituations":"Strategy/predicate injection where a delegate was never assigned, overloads confusion (passing null intending to select the whole element), reflection-built pipelines where an optional keySelector defaults to null.","solutions":["Pass an explicit identity key selector: DistinctUntilChanged(source, x => x) if you intended element comparison.","If the selector is optional in your API, default it to x => x instead of null before calling.","Null-check the delegate at your API boundary and throw a descriptive exception.","Fix the delegate producer (factory/DI/lookup) that returned null."],"exampleFix":"// before\nFunc<Order, int> key = config.Mode == \"customer\" ? o => o.CustomerId : null;\nvar distinct = orders.DistinctUntilChanged(key);\n// after\nFunc<Order, int> key = config.Mode == \"customer\" ? o => o.CustomerId : (Func<Order, int>)(o => o.Id);\nvar distinct = orders.DistinctUntilChanged(key);","handlingStrategy":"validation","validationCode":"if (keySelector is null) keySelector = static x => x; // or reject with a clear message\nvar result = source.DistinctUntilChanged(keySelector);","typeGuard":"static bool HasSelector<TSource,TKey>(Func<TSource,TKey>? f) => f is not null;","tryCatchPattern":"try\n{\n    var result = source.DistinctUntilChanged(keySelector);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"keySelector\")\n{\n    result = source.DistinctUntilChanged(x => x);\n}","preventionTips":["Default optional key selectors to x => x instead of null","Never store 'whole element' intent as a null selector; express it as x => x","Null-check delegate fields before composing pipelines","Prefer non-nullable Func<> parameter types on your own APIs to force callers to supply selectors"],"tags":["argumentnull","linq","ix-net","null-check"],"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"}