{"record":{"id":"333bb89d9608d643","repo":"dotnet/reactive","slug":"rightdurationselector-join","errorCode":null,"errorMessage":"rightDurationSelector","messagePattern":"rightDurationSelector","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/Join.cs","lineNumber":23,"sourceCode":"using 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);\n                    await subscriptions.AddAsync(rightSubscription).ConfigureAwait(false);\n","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/Join.cs#L5-L41","documentation":"The Join operator throws ArgumentNullException because the rightDurationSelector delegate was null. This delegate maps each right item to its duration observable and is required for windowed join semantics. The library validates it eagerly at call time.","triggerScenarios":"Calling left.Join(right, leftDurationSelector, null, resultSelector) — e.g. the fourth argument was dropped during a refactor or a nullable delegate variable held null.","commonSituations":"Refactors that changed a Join overload and dropped the right duration selector, or delegates resolved from configuration/DI that default to null.","solutions":["Supply a non-null Func<TRight, IAsyncObservable<TRightDuration>> as the fourth argument.","Ensure the delegate variable is initialized before the call.","Use a stub selector returning an appropriate duration observable when the value is genuinely optional."],"exampleFix":"// before\nvar result = left.Join(right, l => l.Duration, null, (l, r) => (l, r));\n// after\nvar result = left.Join(right, l => l.Duration, r => AsyncObservable.Empty<TRightDuration>(), (l, r) => (l, r));","handlingStrategy":"validation","validationCode":"if (rightDurationSelector is null) throw new ArgumentException(\"rightDurationSelector is required\", nameof(rightDurationSelector));","typeGuard":"bool SelectorSet<TR, TD>(Func<TR, IAsyncObservable<TD>>? f) => f is not null;","tryCatchPattern":"try { var joined = left.Join(right, lds, rds, rs); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"rightDurationSelector\") { /* supply the missing selector */ }","preventionTips":["Keep all four Join arguments adjacent in one call; avoid partial construction.","Check overloads after refactors so no selector argument is dropped.","Prefer named arguments (rightDurationSelector:) for readability and refactor safety."],"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"}