dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'type')

Error message

Value cannot be null. (Parameter 'type')

What it means

The static-event overload FromEventPattern(Type type, string eventName) reflects over the given Type to find a static event. A null Type gives reflection no target, so Rx throws ArgumentNullException eagerly at the public API boundary rather than failing inside reflection.

Solutions

  1. Use typeof(SomeClass) directly for the static event's declaring type so the compiler verifies it.
  2. If the Type comes from a string, check Type.GetType/Assembly.GetType result for null before calling and throw a descriptive error.
  3. Load the required assembly before resolving the Type by name.

Example fix

// before
var t = asm.GetType(config.TypeName); // null if name is wrong
var obs = Observable.FromEventPattern(t, config.EventName);
// after
var t = asm.GetType(config.TypeName) ?? throw new InvalidOperationException($"Type {config.TypeName} not found");
var obs = Observable.FromEventPattern(t, config.EventName);
Defensive patterns

Strategy: validation

Validate before calling

if (type is null) throw new InvalidOperationException($"Type '{typeName}' could not be resolved for static event subscription");
var obs = Observable.FromEventPattern(type, eventName);

Type guard

static bool IsValidStaticEvent(Type type, string eventName) =>
    type != null && type.GetEvent(eventName, BindingFlags.Static | BindingFlags.Public) != null;

Try / catch

try
{
    var obs = Observable.FromEventPattern(type, eventName);
}
catch (ArgumentNullException ex) when (ex.ParamName == "type")
{
    // log that the type resolution failed; skip or rethrow with type name
}

Prevention

When it happens

Trigger: Calling Observable.FromEventPattern((Type)null, eventName) — the Type came from typeof on a missing generic argument, Assembly.GetType returning null for an unknown type name, or a Type variable not yet assigned.

Common situations: Reflection-based plugin loading where Assembly.GetType(name) returns null because the type name is wrong or the assembly isn't loaded; generics where typeof(T) is replaced by a nullable Type variable; config-driven static event subscription with a bad type name.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Events.cs:859

        /// <para>
        /// If no SynchronizationContext is present at the point of calling FromEventPattern, add and remove handler invocations are made synchronously on the thread
        /// making the Subscribe or Dispose call, respectively.
        /// </para>
        /// <para>
        /// It's recommended to lift FromEventPattern calls outside event stream query expressions due to the free-threaded nature of Reactive Extensions. Doing so
        /// makes the captured SynchronizationContext predictable. This best practice also reduces clutter of bridging code inside queries, making the query expressions
        /// more concise and easier to understand.
        /// </para>
        /// </remarks>
        /// <seealso cref="ToEventPattern"/>
#if HAS_TRIMMABILITY_ATTRIBUTES
        [RequiresUnreferencedCode(Constants_Core.EventReflectionTrimIncompatibilityMessage)]
#endif
        public static IObservable<EventPattern<object>> FromEventPattern(Type type, string eventName)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            if (eventName == null)
            {
                throw new ArgumentNullException(nameof(eventName));
            }

            return s_impl.FromEventPattern(type, eventName);
        }

        /// <summary>
        /// Converts a static .NET event, conforming to the standard .NET event pattern with an <see cref="EventArgs"/> parameter, to an observable sequence.
        /// Each event invocation is surfaced through an OnNext message in the resulting sequence.
        /// Reflection is used to discover the event based on the specified type and the specified event name.
        /// For conversion of events that don't conform to the standard .NET event pattern, use any of the FromEvent overloads instead.
        /// </summary>
        /// <param name="type">Type that exposes the static event to convert.</param>
        /// <param name="eventName">Name of the event to convert.</param>

View on GitHub (pinned to 94b5d5ab91)