elsa-workflows/elsa-core · error · InvalidOperationException

No Invoke methods were found. Use either Invoke or…

Error message

No Invoke methods were found. Use either Invoke or InvokeAsync

What it means

MiddlewareHelpers.GetInvokeMethod requires every middleware to expose a public instance method named exactly Invoke or InvokeAsync, which the pipeline invokes via reflection. This error is thrown when no such method exists on the middleware type, so the mediator cannot discover its entry point.

Solutions

  1. Add a public instance method named InvokeAsync (or Invoke) accepting the pipeline context and next delegate, matching the IMiddleware contract for your pipeline.
  2. Implement the proper interface (IMiddleware, ICommandMiddleware, etc.) to get the method signature right.
  3. Make the method instance-level and public (not static, not private).
  4. Verify you registered the intended middleware type, not an unrelated class, in the pipeline configuration.

Example fix

// before
public class MyMiddleware : ICommandMiddleware
{
    public ValueTask HandleAsync(CommandContext context, CommandMiddlewareDelegate next) => next(context); // wrong name
}

// after
public class MyMiddleware : ICommandMiddleware
{
    public ValueTask InvokeAsync(CommandContext context, CommandMiddlewareDelegate next) => next(context);
Defensive patterns

Strategy: validation

Validate before calling

// Before registering middleware, ensure a public instance Invoke/InvokeAsync exists:
var hasInvoke = middlewareType.GetMethods(BindingFlags.Instance | BindingFlags.Public)
    .Any(m => m.Name is "Invoke" or "InvokeAsync");
if (!hasInvoke)
    throw new InvalidOperationException($"{middlewareType.Name} is missing a public Invoke/InvokeAsync method.");

Type guard

static bool IsMiddleware(Type t) =>
    typeof(Elsa.Mediator.Contracts.IMiddleware).IsAssignableFrom(t) &&
    t.GetMethods(BindingFlags.Instance | BindingFlags.Public)
     .Any(m => m.Name is "Invoke" or "InvokeAsync");

Try / catch

try
{
    pipeline.AddMiddleware(typeof(MyMiddleware));
}
catch (InvalidOperationException ex) when (ex.Message.Contains("No Invoke methods were found"))
{
    logger.LogError(ex, "{Type} does not follow the middleware Invoke convention", typeof(MyMiddleware).Name);
    throw;
}

Prevention

When it happens

Trigger: Registering a middleware class that does not implement the Invoke/InvokeAsync convention and does not implement IMiddleware/ICommandMiddleware; renaming the method (e.g. to HandleAsync or InvokeInternal); middleware defined with a static Invoke method (statics are excluded by BindingFlags.Instance); method made private/protected; wrong type registered as middleware (e.g. a handler or service class by mistake).

Common situations: Writing a custom pipeline middleware from scratch and missing the convention; a typo like InvokeeAsync or InvokeAsnyc; refactoring that renamed the method without updating the pipeline contract; passing the wrong type into middleware registration during DI setup.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/f3ac426eb7bc1d13. Report an issue: GitHub.

Appendix: source

Thrown at src/common/Elsa.Mediator/Middleware/MiddlewareHelpers.cs:28

    /// <summary>
    /// Gets the Invoke or InvokeAsync method from the middleware type.
    /// </summary>
    /// <param name="middleware">The middleware type.</param>
    /// <returns>The Invoke or InvokeAsync method.</returns>
    /// <exception cref="InvalidOperationException">Thrown when the Invoke or InvokeAsync method cannot be found or the return type is not Task or ValueTask.</exception>
    public static MethodInfo GetInvokeMethod(Type middleware)
    {
        const string invokeMethodName = "Invoke";
        const string invokeAsyncMethodName = "InvokeAsync";
        var methods = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public);
        var invokeMethods = methods.Where(m => string.Equals(m.Name, invokeMethodName, StringComparison.Ordinal) || string.Equals(m.Name, invokeAsyncMethodName, StringComparison.Ordinal)).ToArray();

        switch (invokeMethods.Length)
        {
            case > 1:
                throw new InvalidOperationException("Multiple Invoke methods were found. Use either Invoke or InvokeAsync.");
            case 0:
                throw new InvalidOperationException("No Invoke methods were found. Use either Invoke or InvokeAsync");
        }

        var methodInfo = invokeMethods[0];

        if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType) && !typeof(ValueTask).IsAssignableFrom(methodInfo.ReturnType))
            throw new InvalidOperationException($"The {methodInfo.Name} method must return Task or ValueTask");

        return methodInfo;
    }
}

View on GitHub (pinned to fe9217bdfa)