{"record":{"id":"9d7c67a8feaa28ba","repo":"dotnet/reactive","slug":"leftdurationselector-join","errorCode":null,"errorMessage":"leftDurationSelector","messagePattern":"leftDurationSelector","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/Join.cs","lineNumber":21,"sourceCode":"// See the LICENSE file in the project root for more information. \n\nusing System.Collections.Generic;\nusing System.Reactive.Disposables;\nusing 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);","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/Join.cs#L3-L39","documentation":"The Join operator throws ArgumentNullException because the leftDurationSelector delegate was null. This delegate maps each left item to the observable that governs how long it stays joinable; without it the operator cannot function, so it is validated eagerly. The library throws immediately at operator creation rather than during subscription.","triggerScenarios":"Calling left.Join(right, null, rightDurationSelector, resultSelector) — typically the lambda was omitted or a delegate variable was null.","commonSituations":"Storing selector delegates in fields/dependency-injected services that were never assigned, or calling via reflection/dynamic wrappers that pass null defaults.","solutions":["Supply a non-null Func<TLeft, IAsyncObservable<TLeftDuration>> as the third argument.","Verify the delegate variable is assigned before the Join call (guard with a null check or default lambda).","If durations are irrelevant, return an empty/never-completing observable from the selector as appropriate instead of passing null."],"exampleFix":"// before\nvar result = left.Join(right, null, r => r.Duration, (l, r) => (l, r));\n// after\nvar result = left.Join(right, l => AsyncObservable.Empty<TLeftDuration>(), r => r.Duration, (l, r) => (l, r));","handlingStrategy":"validation","validationCode":"if (leftDurationSelector is null) throw new ArgumentException(\"leftDurationSelector is required\", nameof(leftDurationSelector));","typeGuard":"bool SelectorSet<TL, TD>(Func<TL, IAsyncObservable<TD>>? f) => f is not null;","tryCatchPattern":"try { var joined = left.Join(right, lds, rds, rs); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"leftDurationSelector\") { /* supply a default selector and retry */ }","preventionTips":["Pass lambdas inline to Join rather than via nullable delegate fields.","Assign DI-injected delegate dependencies in the constructor, not lazily.","Use default selector helpers (e.g. _ => AsyncObservable.Empty<T>()) when a duration is irrelevant."],"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"}