{"record":{"id":"66b9e8742705fcad","repo":"dotnet/reactive","slug":"resultselector-join","errorCode":null,"errorMessage":"resultSelector","messagePattern":"resultSelector","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/Join.cs","lineNumber":25,"sourceCode":"using System.Threading;\nusing System.Threading.Tasks;\n\nnamespace System.Reactive.Linq\n{\n    public partial class AsyncObservable\n    {\n        public static IAsyncObservable<TResult> Join<TLeft, TRight, TLeftDuration, TRightDuration, TResult>(this IAsyncObservable<TLeft> left, IAsyncObservable<TRight> right, Func<TLeft, IAsyncObservable<TLeftDuration>> leftDurationSelector, Func<TRight, IAsyncObservable<TRightDuration>> rightDurationSelector, Func<TLeft, TRight, TResult> resultSelector)\n        {\n            if (left == null)\n                throw new ArgumentNullException(nameof(left));\n            if (right == null)\n                throw new ArgumentNullException(nameof(right));\n            if (leftDurationSelector == null)\n                throw new ArgumentNullException(nameof(leftDurationSelector));\n            if (rightDurationSelector == null)\n                throw new ArgumentNullException(nameof(rightDurationSelector));\n            if (resultSelector == null)\n                throw new ArgumentNullException(nameof(resultSelector));\n\n            return CreateAsyncObservable<TResult>.From(\n                left,\n                (right, leftDurationSelector, rightDurationSelector, resultSelector),\n                static async (left, state, observer) =>\n                {\n                    var subscriptions = new CompositeAsyncDisposable();\n\n                    var (leftObserver, rightObserver, disposable) = AsyncObserver.Join(observer, subscriptions, state.leftDurationSelector, state.rightDurationSelector, state.resultSelector);\n\n                    var leftSubscription = await left.SubscribeSafeAsync(leftObserver).ConfigureAwait(false);\n                    await subscriptions.AddAsync(leftSubscription).ConfigureAwait(false);\n\n                    var rightSubscription = await state.right.SubscribeSafeAsync(rightObserver).ConfigureAwait(false);\n                    await subscriptions.AddAsync(rightSubscription).ConfigureAwait(false);\n\n                    return disposable;\n                });","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/Join.cs#L7-L43","documentation":"The Join operator throws ArgumentNullException because the resultSelector delegate was null. The result selector combines each matched (left, right) pair into a TResult and is essential to the operator's output. It is validated up front so the failure occurs at operator construction, not on first match.","triggerScenarios":"Calling left.Join(right, leftDurationSelector, rightDurationSelector, null) — commonly caused by forgetting the final lambda or a null delegate field.","commonSituations":"Copy-paste of Join calls where the result lambda was removed, or generic helper methods that forward a null selector parameter.","solutions":["Pass a non-null Func<TLeft, TRight, TResult> as the fifth argument.","If you truly need pass-through, use (l, r) => (l, r) tuple selection instead of null.","Check any wrapper/helper API that forwards selectors and ensure defaults are non-null."],"exampleFix":"// before\nvar result = left.Join(right, l => l.Duration, r => r.Duration, null);\n// after\nvar result = left.Join(right, l => l.Duration, r => r.Duration, (l, r) => new Match(l, r));","handlingStrategy":"validation","validationCode":"if (resultSelector is null) throw new ArgumentException(\"resultSelector is required\", nameof(resultSelector));","typeGuard":"bool SelectorSet<TL, TR, TRes>(Func<TL, TR, TRes>? f) => f is not null;","tryCatchPattern":"try { var joined = left.Join(right, lds, rds, rs); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"resultSelector\") { /* supply a selector, e.g. tuple projection */ }","preventionTips":["Always provide a projection lambda; use (l, r) => (l, r) for pass-through.","Avoid nullable Func fields for selectors; construct them at the call site.","Review copy-pasted Join calls for removed lambda arguments."],"tags":["argument-null","reactive-operators","delegate"],"backgroundTag":"null-argument","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}