dotnet/reactive · error · InvalidOperationException
Strings_Linq.EVENT_MUST_RETURN_VOID
Error message
Strings_Linq.EVENT_MUST_RETURN_VOID
What it means
Event delegates must return void; the .NET event pattern defines handlers with a void return. If the delegate's Invoke method returns a non-void type, Rx cannot treat it as an event handler and GetEventMethods throws InvalidOperationException.
Solutions
- Use a void-returning delegate (Action/EventHandler style) for the event.
- If the API returns values, model it as a method call or use Observable.FromAsyncPattern-style adapters instead of FromEventPattern.
- Wrap the value-returning callback manually with Observable.Create.
Example fix
// before public delegate bool Validate(object sender, EventArgs e); // after public delegate void Validate(object sender, EventArgs e); // or EventHandler
Defensive patterns
Strategy: validation
Validate before calling
var invoke = delegateType.GetMethod("Invoke");
if (invoke?.ReturnType != typeof(void))
throw new ArgumentException("Event delegates must return void"); Try / catch
try
{
var src = Observable.FromEventPattern(target, eventName);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("void"))
{
// adapt the callback-style API with Observable.Create instead
} Prevention
- Only declare void-returning delegates for events.
- Treat value-returning callbacks as methods/async calls, not events.
- Lint custom delegate declarations used as event types.
When it happens
Trigger: Passing a delegate type (e.g. Func<int, string, bool>) to FromEventPattern/FromEvent where the handler returns a value.
Common situations: Callback-style APIs mistakenly exposed as events; custom delegates with return values used for observer-style notifications; hand-rolled add/remove accessors accepting value-returning delegates.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Strings_Linq.EVENT_REMOVE_METHOD_SHOULD_TAKE_ONE_PARAMETER
- Strings_Linq.EVENT_PATTERN_REQUIRES_TWO_PARAMETERS
- conversion
- ArgumentNull_Generic
- conversion
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/1b125e1738fd3ff5.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Internal/ReflectionUtils.cs:92
if (parameters.Length != 2)
{
throw new InvalidOperationException(Strings_Linq.EVENT_PATTERN_REQUIRES_TWO_PARAMETERS);
}
if (!typeof(TSender).IsAssignableFrom(parameters[0].ParameterType))
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.EVENT_SENDER_NOT_ASSIGNABLE, typeof(TSender).FullName));
}
if (!typeof(TEventArgs).IsAssignableFrom(parameters[1].ParameterType))
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.EVENT_ARGS_NOT_ASSIGNABLE, typeof(TEventArgs).FullName));
}
if (invokeMethod.ReturnType != typeof(void))
{
throw new InvalidOperationException(Strings_Linq.EVENT_MUST_RETURN_VOID);
}
}
/// <summary>
/// Determine whether a type represents a WinRT event registration token
/// (https://learn.microsoft.com/en-us/uwp/api/windows.foundation.eventregistrationtoken).
/// </summary>
/// <param name="t">The type to check.</param>
/// <returns>True if this represents a WinRT event registration token</returns>
/// <remarks>
/// <para>
/// We used to perform a simple comparison with typeof(EventRegistrationToken), but the
/// introduction of C#/WinRT has made this problematic. Before C#/WinRT, the .NET
/// projection of WinRT's Windows.Foundation.EventRegistrationToken type was
/// System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken. But that type is
/// associated with the old WinRT interop mechanisms in which the CLR works directly with
/// WinMD. That was how it worked up as far as .NET Core 3.1, and it's still how .NET
/// Framework works, but this direct WinMD support was removed in .NET 5.0.View on GitHub (pinned to 94b5d5ab91)