LuckyPennySoftware/MediatR · error · InvalidOperationException

Could not create task for action method {actionForException.

Error message

Could not create task for action method {actionForException.MethodInfo}.

What it means

Thrown at runtime by RequestExceptionActionProcessorBehavior when invoking an exception action's Execute method via reflection returns null. MediatR calls actionForException.MethodInfo.Invoke(...) and coalesces the result; Execute must return a Task, so null means the implementation violated that contract.

Source

Thrown at src/MediatR/Pipeline/RequestExceptionActionProcessorBehavior.cs:48

            return await next(cancellationToken).ConfigureAwait(false);
        }
        catch (Exception exception)
        {
            var exceptionTypes = GetExceptionTypes(exception.GetType());

            var actionsForException = exceptionTypes
                .SelectMany(exceptionType => GetActionsForException(exceptionType, request))
                .GroupBy(static actionForException => actionForException.Action.GetType())
                .Select(static actionForException => actionForException.First())
                .Select(static actionForException => (MethodInfo: GetMethodInfoForAction(actionForException.ExceptionType), actionForException.Action))
                .ToList();

            foreach (var actionForException in actionsForException)
            {
                try
                {
                    await ((Task)(actionForException.MethodInfo.Invoke(actionForException.Action, new object[] { request, exception, cancellationToken })
                                  ?? throw new InvalidOperationException($"Could not create task for action method {actionForException.MethodInfo}."))).ConfigureAwait(false);
                }
                catch (TargetInvocationException invocationException) when (invocationException.InnerException != null)
                {
                    // Unwrap invocation exception to throw the actual error
                    ExceptionDispatchInfo.Capture(invocationException.InnerException).Throw();
                }
            }

            throw;
        }
    }

    private static IEnumerable<Type> GetExceptionTypes(Type? exceptionType)
    {
        while (exceptionType != null && exceptionType != typeof(object))
        {
            yield return exceptionType;
            exceptionType = exceptionType.BaseType;

View on GitHub (pinned to 916ef1b3d6)

Solutions

  1. Ensure Execute always returns a non-null Task; for async methods use `async Task` and never return null/default; for sync use `return Task.CompletedTask;`.
  2. If the action has nothing to do, return Task.CompletedTask rather than null.
  3. Audit each IRequestExceptionAction implementation for unreachable-but-compiler-accepted null return paths.

Example fix

// before
public class MyAction : IRequestExceptionAction<MyRequest, MyException>
{
    public Task Execute(MyRequest req, MyException ex, CancellationToken ct)
        => null; // throws at runtime
}

// after
public class MyAction : IRequestExceptionAction<MyRequest, MyException>
{
    public Task Execute(MyRequest req, MyException ex, CancellationToken ct)
        => Task.CompletedTask;
}
Defensive patterns

Strategy: validation

Validate before calling

// Cannot statically validate reflection results; ensure contract via code review.
// Unit test every IRequestExceptionAction to assert Execute returns non-null:
[Fact]
public async Task Execute_NeverReturnsNull()
{
    var sut = new MyExceptionAction();
    var task = sut.Execute(new MyRequest(), new MyException(), default);
    Assert.NotNull(task);
    await task;
}

Try / catch

// Wrap mediator.Send in outer try/catch; this error is a contract violation
// in user code, not a transient condition. Catch to log and fail fast.
try { await mediator.Send(request, ct); }
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Could not create task"))
{
    logger.LogError(ex, "Exception action returned null Task");
    throw;
}

Prevention

When it happens

Trigger: An IRequestExceptionAction<TRequest, TException>.Execute implementation that returns null (e.g. an async method whose code path returns null or `await` is missing on a method returning null), or a sync method declared with a Task return type that does not return a Task instance.

Common situations: Hand-written Execute that does `return null;` or `return default;`; a method declared `public Task Execute(...)` with no return statement in a code path; miscompiled/dynamically-generated action types.

Related errors


AI-assisted analysis of LuckyPennySoftware/MediatR@916ef1b3d6 (2026-08-13). Data as JSON: /api/errors/355d91271613f85d. Report an issue: GitHub.