{"record":{"id":"0c6879b310a64484","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-resultselector-selectmany","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'resultSelector')","messagePattern":"Value cannot be null\\. \\(Parameter 'resultSelector'\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/SelectMany.cs","lineNumber":166,"sourceCode":"                (collectionSelector, resultSelector),\n                static async (source, state, observer) =>\n                {\n                    var (sink, inner) = AsyncObserver.SelectMany(observer, state.collectionSelector, state.resultSelector);\n\n                    var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);\n\n                    return StableCompositeAsyncDisposable.Create(subscription, inner);\n                });\n        }\n\n        public static IAsyncObservable<TResult> SelectMany<TSource, TCollection, TResult>(this IAsyncObservable<TSource> source, Func<TSource, int, ValueTask<IAsyncObservable<TCollection>>> collectionSelector, Func<TSource, int, TCollection, int, ValueTask<TResult>> resultSelector)\n        {\n            if (source == null)\n                throw new ArgumentNullException(nameof(source));\n            if (collectionSelector == null)\n                throw new ArgumentNullException(nameof(collectionSelector));\n            if (resultSelector == null)\n                throw new ArgumentNullException(nameof(resultSelector));\n\n            return CreateAsyncObservable<TResult>.From(\n                source,\n                (collectionSelector, resultSelector),\n                static async (source, state, observer) =>\n                {\n                    var (sink, inner) = AsyncObserver.SelectMany(observer, state.collectionSelector, state.resultSelector);\n\n                    var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);\n\n                    return StableCompositeAsyncDisposable.Create(subscription, inner);\n                });\n        }\n    }\n\n    public partial class AsyncObserver\n    {\n        public static (IAsyncObserver<TSource>, IAsyncDisposable) SelectMany<TSource, TResult>(IAsyncObserver<TResult> observer, Func<TSource, IAsyncObservable<TResult>> selector)","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/SelectMany.cs#L148-L184","documentation":"The async SelectMany operator on IAsyncObservable<TSource> throws ArgumentNullException because its resultSelector parameter was null. This operator requires a function that combines each source element with each inner-collection element to produce the final result; without it the operator cannot be constructed. The library validates all delegate arguments eagerly at operator-creation time rather than failing later during subscription.","triggerScenarios":"Calling AsyncObservable.SelectMany(source, collectionSelector, resultSelector) with a null third argument, e.g. SelectMany(source, x => inner, (Func<TSource,TCollection,TResult>)null), or passing a resultSelector variable that was never assigned.","commonSituations":"Conditional delegate assignment (resultSelector only assigned in one branch), passing the output of a factory/lookup method that returned null, refactoring from a two-argument SelectMany overload to the three-argument one and forgetting the extra argument, or dynamic composition where a selector map has no entry.","solutions":["Pass a non-null resultSelector lambda, e.g. (x, y) => Combine(x, y).","If the result is just the inner element, use the two-argument overload SelectMany(source, collectionSelector) instead of passing a null selector.","Check where the delegate comes from (config, dictionary lookup, optional parameter default) and default it to a valid function instead of null.","Guard the call site: if (resultSelector == null) throw/log before invoking SelectMany so the failure points at your code."],"exampleFix":"// before\nvar qs = AsyncObservable.SelectMany(source, x => GetInner(x), null);\n\n// after\nvar qs = AsyncObservable.SelectMany(source, x => GetInner(x), (src, inner) => new Result(src.Id, inner));","handlingStrategy":"validation","validationCode":"if (source is null) throw new ArgumentNullException(nameof(source));\nif (collectionSelector is null) throw new ArgumentNullException(nameof(collectionSelector));\nif (resultSelector is null) throw new ArgumentNullException(nameof(resultSelector));","typeGuard":"static bool IsValidSelectManyArgs<TSource, TCollection, TResult>(\n    IAsyncObservable<TSource> source,\n    Func<TSource, IAsyncObservable<TCollection>> collectionSelector,\n    Func<TSource, TCollection, TResult> resultSelector)\n    => source is not null && collectionSelector is not null && resultSelector is not null;","tryCatchPattern":"try\n{\n    var qs = AsyncObservable.SelectMany(source, collectionSelector, resultSelector);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"resultSelector\")\n{\n    // provide default projection or surface config error\n    resultSelector = (src, inner) => default;\n}","preventionTips":["Never pass nullable delegate parameters straight into operator calls; default them at the boundary.","Prefer method groups over variables so the compiler enforces non-null references.","When a delegate comes from configuration or a registry, validate it right after resolution."],"tags":["argument-null","asyncrx","linq-operators","selectmany"],"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"}