dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'observer')

Error message

Value cannot be null. (Parameter 'observer')

What it means

Producer<TSource>.Subscribe(IObserver<TSource>) validates its observer argument and throws ArgumentNullException when null. Producer is the base class for all observable factories in System.Reactive, so subscribing a null observer is rejected immediately before any subscription machinery runs.

Solutions

  1. Ensure a valid non-null IObserver<TSource> is passed; create one (e.g. Observer.Create<TSource>(...) or AnonymousObserver) instead of null.
  2. Guard the observer argument at the call site and handle the null case before subscribing.
  3. If you intended 'do nothing', use Observer.Empty<TSource>() or a no-op observer, not null.

Example fix

// before
IObserver<int> obs = condition ? BuildObserver() : null;
source.Subscribe(obs);
// after
IObserver<int> obs = condition ? BuildObserver() : Observer.Create<int>(_ => { });
source.Subscribe(obs);
Defensive patterns

Strategy: validation

Validate before calling

if (observer == null) throw new ArgumentException("observer must not be null");
source.Subscribe(observer);

Type guard

bool IsValid<T>(IObserver<T>? o) => o is not null;
if (IsValid(observer)) source.Subscribe(observer);

Try / catch

try { source.Subscribe(observer); } catch (ArgumentNullException ex) when (ex.ParamName == "observer") { /* supply fallback observer */ }

Prevention

When it happens

Trigger: Calling source.Subscribe(null) or passing a null IObserver<TSource> variable/return value of a factory method into Subscribe.

Common situations: A method that builds observers conditionally returns null on some code path; refactoring changed a lambda to an IObserver variable that was never assigned; interop code casts fail silently to null.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/fab63302146eaa40. Report an issue: GitHub.

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Internal/Producer.cs:34

        IDisposable SubscribeRaw(IObserver<TSource> observer, bool enableSafeguard);
    }

    /// <summary>
    /// Base class for implementation of query operators, providing performance benefits over the use of Observable.Create.
    /// </summary>
    /// <typeparam name="TSource">Type of the resulting sequence's elements.</typeparam>
    internal abstract class BasicProducer<TSource> : IProducer<TSource>
    {
        /// <summary>
        /// Publicly visible Subscribe method.
        /// </summary>
        /// <param name="observer">Observer to send notifications on. The implementation of a producer must ensure the correct message grammar on the observer.</param>
        /// <returns>IDisposable to cancel the subscription. This causes the underlying sink to be notified of unsubscription, causing it to prevent further messages from being sent to the observer.</returns>
        public IDisposable Subscribe(IObserver<TSource> observer)
        {
            if (observer == null)
            {
                throw new ArgumentNullException(nameof(observer));
            }

            return SubscribeRaw(observer, enableSafeguard: true);
        }

        public IDisposable SubscribeRaw(IObserver<TSource> observer, bool enableSafeguard)
        {
            IDisposable run;
            ISafeObserver<TSource>? safeObserver = null;

            //
            // See AutoDetachObserver.cs for more information on the safeguarding requirement and
            // its implementation aspects.
            //
            if (enableSafeguard)
            {
                observer = safeObserver = SafeObserver<TSource>.Wrap(observer);
            }

View on GitHub (pinned to 94b5d5ab91)