{"record":{"id":"a88e85cc1df1ff15","repo":"dotnet/reactive","slug":"right","errorCode":null,"errorMessage":"right","messagePattern":"right","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/Join.cs","lineNumber":19,"sourceCode":"﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT License.\n// 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);","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/Join.cs#L1-L37","documentation":"The Join operator throws ArgumentNullException because the required 'right' (second source) observable was null. This library validates all delegate and observable arguments up front so failures surface at call time rather than mid-subscription. Reactive pipelines composed with a null source cannot ever produce values, so it fails fast.","triggerScenarios":"Calling left.Join(right, leftDurationSelector, rightDurationSelector, resultSelector) with right == null, e.g. a factory/config method returned null instead of an IAsyncObservable<TRight>.","commonSituations":"Building join sources conditionally (a missing optional stream yields null), wiring up sources from a dictionary/config lookup that misses a key, or refactoring where a source field was never initialized.","solutions":["Pass a non-null IAsyncObservable<TRight> as the second argument to Join.","If the right source may be absent, substitute an empty observable (e.g. AsyncObservable.Empty<TRight>()) instead of null.","Check where the right observable is produced; fix the upstream factory/lookup so it never returns null."],"exampleFix":"// before\nvar result = left.Join(right!, l => l.Duration, r => r.Duration, (l, r) => (l, r));\n// after\nif (right == null) right = AsyncObservable.Empty<TRight>();\nvar result = left.Join(right, l => l.Duration, r => r.Duration, (l, r) => (l, r));","handlingStrategy":"validation","validationCode":"if (right is null) throw new ArgumentException(\"right source must be provided before joining\", nameof(right));","typeGuard":"bool RightReady<TRight>(IAsyncObservable<TRight>? r) => r is not null;","tryCatchPattern":"try { var joined = left.Join(right, lds, rds, rs); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"right\") { /* substitute empty source or fail fast */ }","preventionTips":["Never return null from methods that produce observables; return AsyncObservable.Empty instead.","Initialize all source fields before composing pipelines.","Enable nullable reference types (C# 8+) so null sources are caught at compile time."],"tags":["argument-null","reactive-operators","join"],"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"}