{"record":{"id":"efa49c5b232d64fd","repo":"elsa-workflows/elsa-core","slug":"the-methodinfo-name-method-must-return-task-or-valuetask-efa49c","errorCode":null,"errorMessage":"The {methodInfo.Name} method must return Task or ValueTask","messagePattern":"The (.+?) method must return Task or ValueTask","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"critical","filePath":"src/modules/Elsa.Workflows.Core/Pipelines/MiddlewareHelpers.cs","lineNumber":25,"sourceCode":"    public static MethodInfo GetInvokeMethod(Type middleware)\n    {\n        const string invokeMethodName = \"Invoke\";\n        const string invokeAsyncMethodName = \"InvokeAsync\";\n        var methods = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public);\n        var invokeMethods = methods.Where(m => string.Equals(m.Name, invokeMethodName, StringComparison.Ordinal) || string.Equals(m.Name, invokeAsyncMethodName, StringComparison.Ordinal)).ToArray();\n\n        switch (invokeMethods.Length)\n        {\n            case > 1:\n                throw new InvalidOperationException(\"Multiple Invoke methods were found. Use either Invoke or InvokeAsync.\");\n            case 0:\n                throw new InvalidOperationException(\"No Invoke methods were found. Use either Invoke or InvokeAsync\");\n        }\n\n        var methodInfo = invokeMethods[0];\n\n        if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType) && !typeof(ValueTask).IsAssignableFrom(methodInfo.ReturnType))\n            throw new InvalidOperationException($\"The {methodInfo.Name} method must return Task or ValueTask\");\n\n        return methodInfo;\n    }\n}","sourceCodeStart":7,"sourceCodeEnd":29,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Workflows.Core/Pipelines/MiddlewareHelpers.cs#L7-L29","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\npublic void InvokeAsync(WorkflowMiddlewareContext context)\n{\n    // sync work\n}\n\n// after\npublic async Task InvokeAsync(WorkflowMiddlewareContext context)\n{\n    // async work\n}","handlingStrategy":"validation","validationCode":"var method = typeof(MyMiddleware).GetMethod(\"InvokeAsync\");\nif (method == null || !typeof(Task).IsAssignableFrom(method.ReturnType) && !typeof(ValueTask).IsAssignableFrom(method.ReturnType))\n    throw new InvalidOperationException(\"Middleware Invoke/InvokeAsync must return Task or ValueTask\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["csharp","async","middleware","reflection"],"backgroundTag":"invalid-argument-value","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}