{"record":{"id":"b21aee2c400b239f","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-gate-observer-extensions","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'gate')","messagePattern":"Value cannot be null\\. \\(Parameter 'gate'\\)","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Observer.Extensions.cs","lineNumber":257,"sourceCode":"        /// <param name=\"observer\">The observer whose callbacks should be synchronized.</param>\n        /// <param name=\"gate\">Gate object to synchronize each observer call on.</param>\n        /// <returns>An observer that delivers callbacks to the specified observer in a synchronized manner.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"observer\"/> or <paramref name=\"gate\"/> is null.</exception>\n        /// <remarks>\n        /// Because a <see cref=\"Monitor\">Monitor</see> is used to perform the synchronization, there's no protection against reentrancy from the same thread.\n        /// Hence, overlapped observer callbacks are still possible, which is invalid behavior according to the observer grammar. In order to protect against this behavior as\n        /// well, use the <see cref=\"Synchronize{T}(IObserver{T}, AsyncLock)\"/> overload.\n        /// </remarks>\n        public static IObserver<T> Synchronize<T>(IObserver<T> observer, object gate)\n        {\n            if (observer == null)\n            {\n                throw new ArgumentNullException(nameof(observer));\n            }\n\n            if (gate == null)\n            {\n                throw new ArgumentNullException(nameof(gate));\n            }\n\n            return new SynchronizedObserver<T>(observer, gate);\n        }\n\n        /// <summary>\n        /// Synchronizes access to the observer such that its callback methods cannot be called concurrently, using the specified asynchronous lock to protect against concurrent and reentrant access.\n        /// This overload is useful when coordinating multiple observers that access shared state by synchronizing on a common asynchronous lock.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of the elements received by the source observer.</typeparam>\n        /// <param name=\"observer\">The observer whose callbacks should be synchronized.</param>\n        /// <param name=\"asyncLock\">Gate object to synchronize each observer call on.</param>\n        /// <returns>An observer that delivers callbacks to the specified observer in a synchronized manner.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"observer\"/> or <paramref name=\"asyncLock\"/> is null.</exception>\n        public static IObserver<T> Synchronize<T>(IObserver<T> observer, AsyncLock asyncLock)\n        {\n            if (observer == null)\n            {","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Observer.Extensions.cs#L239-L275","documentation":"System.Reactive's Observer.Synchronize<T>(IObserver<T>, object gate) throws ArgumentNullException when the gate object is null. The gate is the lock object used to serialize OnNext/OnError/OnCompleted calls to the wrapped observer, so it is mandatory. The library fails fast at the extension-method boundary rather than throwing later from inside SynchronizedObserver.","triggerScenarios":"Calling Observer.Synchronize(observer, gate) with a null second argument — e.g. passing an uninitialized lock field, a null returned from a factory, or accidentally calling the (observer, gate) overload when intending the (observer, AsyncLock) overload with a null AsyncLock.","commonSituations":"A lock object initialized lazily but used before initialization; refactoring that removed the lock allocation; confusion between the object-gate and AsyncLock overloads after a null asyncLock propagates from dependency injection.","solutions":["Pass a non-null lock object, e.g. new object(), as the gate","Ensure the field holding the gate is initialized before the Synchronize call (initialize inline: readonly object _gate = new object();)","If you meant the AsyncLock overload, pass a new AsyncLock() instead","Add a null check or require a non-null gate at the caller's API boundary"],"exampleFix":"// before\nobject gate = GetLock(); // returns null\nvar synced = Observer.Synchronize(observer, gate);\n// after\nvar gate = new object();\nvar synced = Observer.Synchronize(observer, gate);","handlingStrategy":"validation","validationCode":"if (observer is null) throw new ArgumentNullException(nameof(observer));\nif (gate is null) gate = new object();\nvar synced = Observer.Synchronize(observer, gate);","typeGuard":"static bool IsValidGate(object? gate) => gate is not null;","tryCatchPattern":"try { var synced = Observer.Synchronize(observer, gate); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"gate\")\n{\n    gate = new object();\n    var synced = Observer.Synchronize(observer, gate);\n}","preventionTips":["Initialize lock fields inline: private readonly object _gate = new object();","Never leave lock references nullable if they are always required","Prefer the AsyncLock overload when you already have an AsyncLock instance","Assert gate non-null in unit tests for subscription setup code"],"tags":["null-argument","dotnet","rx","argument-validation"],"backgroundTag":"null-argument","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}