{"record":{"id":"f2c67e470bcaeafe","repo":"LuckyPennySoftware/MediatR","slug":"did-not-return-a-task-from-the-exception-handler","errorCode":null,"errorMessage":"Did not return a Task from the exception handler.","messagePattern":"Did not return a Task from the exception handler\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/MediatR/Pipeline/RequestExceptionProcessorBehavior.cs","lineNumber":50,"sourceCode":"        catch (Exception exception)\n        {\n            var state = new RequestExceptionHandlerState<TResponse>();\n\n            var exceptionTypes = GetExceptionTypes(exception.GetType());\n\n            var handlersForException = exceptionTypes\n                .SelectMany(exceptionType => GetHandlersForException(exceptionType, request))\n                .GroupBy(static handlerForException => handlerForException.Handler.GetType())\n                .Select(static handlerForException => handlerForException.First())\n                .Select(static handlerForException => (MethodInfo: GetMethodInfoForHandler(handlerForException.ExceptionType), handlerForException.Handler))\n                .ToList();\n\n            foreach (var handlerForException in handlersForException)\n            {\n                try\n                {\n                    await ((Task) (handlerForException.MethodInfo.Invoke(handlerForException.Handler, new object[] { request, exception, state, cancellationToken })\n                                   ?? throw new InvalidOperationException(\"Did not return a Task from the exception handler.\"))).ConfigureAwait(false);\n                }\n                catch (TargetInvocationException invocationException) when (invocationException.InnerException != null)\n                {\n                    // Unwrap invocation exception to throw the actual error\n                    ExceptionDispatchInfo.Capture(invocationException.InnerException).Throw();\n                }\n\n                if (state.Handled)\n                {\n                    break;\n                }\n            }\n\n            if (!state.Handled)\n            {\n                throw;\n            }\n","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/LuckyPennySoftware/MediatR/blob/916ef1b3d68ccdc96db8f914eaf1b32fc7db52c5/src/MediatR/Pipeline/RequestExceptionProcessorBehavior.cs#L32-L68","documentation":"Thrown at runtime by RequestExceptionProcessorBehavior when an exception handler's Handle method (invoked via reflection) returns null instead of a Task. The handler contract is IRequestExceptionHandler<TRequest,TResponse,TException>.Handle returning Task and setting state.Handled; null violates it.","triggerScenarios":"An IRequestExceptionHandler implementation whose Handle returns null (e.g. `return null;`, `return default;`, or an async method whose code path returns null).","commonSituations":"Custom exception handler with a missed return path; copy-pasting a void-style handler into a Task-returning signature; dynamic/generated handler that misbehaves.","solutions":["Make Handle always return a non-null Task; use `async Task` and never return null, or `return Task.CompletedTask;` for sync.","If you intend not to handle the exception, set state.Handled = false and return Task.CompletedTask instead of null.","Add a unit test asserting Handle returns non-null for all code paths."],"exampleFix":"// before\npublic class MyHandler : IRequestExceptionHandler<MyReq, MyResp, MyException>\n{\n    public Task Handle(MyReq req, MyException ex,\n        RequestExceptionHandlerState<MyResp> state, CancellationToken ct)\n        => null;\n}\n\n// after\npublic class MyHandler : IRequestExceptionHandler<MyReq, MyResp, MyException>\n{\n    public async Task Handle(MyReq req, MyException ex,\n        RequestExceptionHandlerState<MyResp> state, CancellationToken ct)\n    {\n        state.SetHandled(new MyResp());\n        await Task.CompletedTask;\n    }\n}","handlingStrategy":"validation","validationCode":"// Unit test that every IRequestExceptionHandler.Handle returns a non-null Task\n[Fact]\npublic async Task Handle_ReturnsTask()\n{\n    var sut = new MyExceptionHandler();\n    var state = new RequestExceptionHandlerState<MyResponse>();\n    var task = sut.Handle(new MyRequest(), new MyException(), state, default);\n    Assert.NotNull(task);\n    await task;\n}","typeGuard":null,"tryCatchPattern":"try { await mediator.Send(request, ct); }\ncatch (InvalidOperationException ex) when (ex.Message == \"Did not return a Task from the exception handler.\")\n{\n    logger.LogError(ex, \"Exception handler returned null Task\");\n    throw;\n}","preventionTips":["Always set state.SetHandled(...) and return a Task from Handle.","Use async Task signature so all paths return a Task."],"tags":["pipeline","exception-handler","reflection","runtime"],"backgroundTag":null,"analyzedSha":"916ef1b3d68ccdc96db8f914eaf1b32fc7db52c5","analyzedAt":"2026-08-13T17:57:04.476Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}