elsa-workflows/elsa-core · critical · InvalidOperationException
The method must return Task or ValueTask
Error message
The {methodInfo.Name} method must return Task or ValueTask What it means
Elsa's MiddlewareHelpers.GetInvokeMethod locates the 'Invoke' or 'InvokeAsync' method on a middleware/custom component type and requires it to return Task or ValueTask so it can be awaited asynchronously. If the discovered method returns void or another non-awaitable type, this InvalidOperationException is thrown. It enforces the async contract of Elsa middleware invoke methods.
Solutions
- Change the middleware's Invoke/InvokeAsync return type to Task or ValueTask.
- If the body has no awaits, return Task.CompletedTask (or make the method async and await nothing is not allowed; prefer ValueTask.FromResult(default)).
- Re-check the middleware registration to ensure the type passed to the pipeline is the one with the corrected signature.
Example fix
// before
public void InvokeAsync(WorkflowMiddlewareContext context)
{
// sync work
}
// after
public async Task InvokeAsync(WorkflowMiddlewareContext context)
{
// async work
} Defensive patterns
Strategy: validation
Validate before calling
var method = typeof(MyMiddleware).GetMethod("InvokeAsync");
if (method == null || !typeof(Task).IsAssignableFrom(method.ReturnType) && !typeof(ValueTask).IsAssignableFrom(method.ReturnType))
throw new InvalidOperationException("Middleware Invoke/InvokeAsync must return Task or ValueTask"); Prevention
- Always declare middleware invoke methods as 'public async Task InvokeAsync(...)'
- Add a unit test that reflects over each custom middleware's signature at startup
- Never port synchronous middleware from Elsa 2.x without updating return types
When it happens
Trigger: Registering a middleware (or workflow component) whose Invoke/InvokeAsync method is declared with a 'void' or synchronous return type, causing typeof(Task).IsAssignableFrom and typeof(ValueTask).IsAssignableFrom checks to both fail at GetInvokeMethod (src/modules/Elsa.Workflows.Core/Pipelines/MiddlewareHelpers.cs:25).
Common situations: Hand-written middleware converted from synchronous code; developers following older Elsa 2.x middleware examples where synchronous signatures were allowed; copy-paste middleware samples renamed to InvokeAsync but left returning void.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- The method must return Task or ValueTask
- Multiple Invoke methods were found. Use either Invoke or…
- No Invoke methods were found. Use either Invoke or…
- Type does not expose an Add method for .
- Can't find method name
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/efa49c5b232d64fd.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Workflows.Core/Pipelines/MiddlewareHelpers.cs:25
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)