PrismLibrary/Prism · error · InvalidOperationException

Could not find Invoke() method for delegate of type

Error message

Could not find Invoke() method for delegate of type {multicastDelegate.GetType().Name}

What it means

MulticastExceptionHandler.HandleAsync resolves the delegate's Invoke method via reflection; if it cannot be found it throws InvalidOperationException. This indicates a delegate type whose Invoke method is not visible via GetMethod, which should never happen for real delegates, so it signals an internal invariant violation or an exotic dynamic proxy type.

Solutions

  1. Pass a real C# delegate (Action, Func, or custom delegate type)
  2. Avoid wrapping handlers in reflection-generated proxies
  3. If mocking, create a true delegate instead of a proxy object
  4. Catch InvalidOperationException around handler registration and log the delegate type

Example fix

// before
object fakeHandler = mockProxy; // not a real delegate
exceptionHandler.Handle(exception, fakeHandler);
// after
ExceptionHandledDelegate handler = (e, p) => Task.CompletedTask;
exceptionHandler.Handle(exception, handler);
Defensive patterns

Strategy: try-catch

Validate before calling

var invoke = multicastDelegate?.GetType().GetMethod("Invoke");
if (invoke is null) throw new InvalidOperationException("Delegate has no Invoke method");

Type guard

bool isUsableDelegate(object d) => d is MulticastDelegate && d.GetType().GetMethod("Invoke") is not null;

Try / catch

try { exceptionHandler.Handle(exception, handler); }
catch (InvalidOperationException ex) { logger.LogError(ex, "Handler delegate unusable: {Type}", handler.GetType().Name); }

Prevention

When it happens

Trigger: Passing a synthetic/proxy object cast to MulticastDelegate whose GetMethod("Invoke") returns null (e.g. certain mocking proxies or dynamically generated types lacking a public Invoke).

Common situations: Registering mocked exception handlers in unit tests with mocking frameworks that generate delegate-like proxies instead of true delegates.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of PrismLibrary/Prism@358118cd64 (2026-09-15). Data as JSON: /api/errors/a15f02cec50fc259. Report an issue: GitHub.

Appendix: source

Thrown at src/Prism.Core/Common/MulticastExceptionHandler.cs:66

        await HandleAsync(exception, parameter);

    /// <summary>
    /// Handles a specified <see cref="Exception"/> asynchronously with a given optional parameter
    /// </summary>
    /// <param name="exception">The <see cref="Exception"/> encountered.</param>
    /// <param name="parameter">An optional parameter which may be passed to a registered callback delegate.</param>
    /// <returns>An asynchronus Task.</returns>
    /// <exception cref="InvalidOperationException"></exception>
    public async Task HandleAsync(Exception exception, object? parameter = null)
    {
        var multicastDelegate = GetDelegate(exception.GetType());

        if (multicastDelegate is null)
            return;

        // Get Invoke() method of the delegate
        var invokeMethod = multicastDelegate.GetType().GetMethod("Invoke")
            ?? throw new InvalidOperationException($"Could not find Invoke() method for delegate of type {multicastDelegate.GetType().Name}");

        var parameters = invokeMethod.GetParameters();
        var arguments = parameters.Length switch
        {
            0 => Array.Empty<object?>(),
            1 => typeof(Exception).IsAssignableFrom(parameters[0].ParameterType) ? [exception] : [parameter],
            2 => typeof(Exception).IsAssignableFrom(parameters[0].ParameterType) ? [exception, parameter] : [parameter, exception],
            _ => throw new InvalidOperationException($"Handler of type {multicastDelegate.GetType().Name} is not supported", exception)
        };

        // Invoke the delegate
        var result = invokeMethod.Invoke(multicastDelegate, arguments);

        // If the handler is async (returns a Task), then we await the task
        if (result is Task task)
        {
            await task;
        }

View on GitHub (pinned to 358118cd64)