{"record":{"id":"d99b268335c1460e","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-rightdurationselector","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'rightDurationSelector')","messagePattern":"Value cannot be null\\. \\(Parameter 'rightDurationSelector'\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Linq/Observable.StandardSequenceOperators.cs","lineNumber":861,"sourceCode":"        {\n            if (left == null)\n            {\n                throw new ArgumentNullException(nameof(left));\n            }\n\n            if (right == null)\n            {\n                throw new ArgumentNullException(nameof(right));\n            }\n\n            if (leftDurationSelector == null)\n            {\n                throw new ArgumentNullException(nameof(leftDurationSelector));\n            }\n\n            if (rightDurationSelector == null)\n            {\n                throw new ArgumentNullException(nameof(rightDurationSelector));\n            }\n\n            if (resultSelector == null)\n            {\n                throw new ArgumentNullException(nameof(resultSelector));\n            }\n\n            return s_impl.GroupJoin(left, right, leftDurationSelector, rightDurationSelector, resultSelector);\n        }\n\n        #endregion\n\n        #region + Join +\n\n        /// <summary>\n        /// Correlates the elements of two sequences based on overlapping durations.\n        /// </summary>\n        /// <typeparam name=\"TLeft\">The type of the elements in the left source sequence.</typeparam>","sourceCodeStart":843,"sourceCodeEnd":879,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Linq/Observable.StandardSequenceOperators.cs#L843-L879","documentation":"GroupJoin threw ArgumentNullException because the rightDurationSelector delegate was null. This selector defines how long each right element participates in the join; the public entry point validates it synchronously before building the query.","triggerScenarios":"Calling left.GroupJoin(right, leftDurationSelector, null, resultSelector) — commonly a null duration lambda from a nullable field or an unconfigured parameter.","commonSituations":"Duration windows read from configuration that were never assigned; helper wrappers passing through optional selectors; incomplete refactors of join call sites.","solutions":["Provide a non-null right duration selector, e.g. r => Observable.Timer(r.Ttl).","Null-check the delegate before the call and surface a descriptive error.","Use Observable.Empty<Unit>() for right elements with zero duration."],"exampleFix":"// before\nvar joined = left.GroupJoin(right, l => l.Window(), _rightDuration, (l, rs) => ...); // _rightDuration null\n// after\nvar joined = left.GroupJoin(right, l => l.Window(), r => Observable.Timer(r.Ttl), (l, rs) => ...);","handlingStrategy":"validation","validationCode":"if (rightDurationSelector == null)\n    rightDurationSelector = _ => Observable.Never<Unit>();","typeGuard":"bool HasRightDuration<TRight>(Func<TRight, IObservable<Unit>>? f) => f is not null;","tryCatchPattern":"try\n{\n    var joined = left.GroupJoin(right, leftDurationSelector, rightDurationSelector, resultSelector);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"rightDurationSelector\")\n{\n    // apply default right-window policy\n}","preventionTips":["Derive right windows from element data (e.g. TTL) rather than nullable config.","Fail fast when window configuration is missing, before query construction.","Prefer explicit lambda arguments over delegate fields for join operators."],"tags":["null-argument","linq","reactive-extensions","groupjoin"],"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"}