elsa-workflows/elsa-core · error · InvalidOperationException

There is no handler to handle the

Error message

There is no handler to handle the {commandType.FullName} command

What it means

Elsa.Mediator's command pipeline resolves exactly one ICommandHandler<TCommand,TResult> from DI for each command being sent. This error is thrown when zero handlers matching the command's type and expected result type are found among the registered ICommandHandler services. It means the command was dispatched but no handler was ever registered in the dependency injection container.

Solutions

  1. Register a handler for the command: services.AddCommandHandler<MyCommandHandler>() (or AddHandlersFrom<MarkerTypeInHandlersAssembly>()).
  2. Verify the handler implements exactly ICommandHandler<TCommand, TResult> with TCommand equal to the sent command's type and TResult equal to the expected ResultType of the Send call.
  3. Confirm the mediator and the handler are registered on the same IServiceCollection / service provider instance that is resolving services.
  4. Check that assembly scanning includes the assembly containing the handler and that the handler is public (non-abstract).
  5. If the command should not require a handler, ensure you are not sending it accidentally (e.g. wrong message type passed to SendAsync instead of PublishAsync).

Example fix

// before
services.AddMediator();
await mediator.SendAsync(new CreateOrderCommand(order)); // throws: no handler

// after
services.AddMediator();
services.AddCommandHandler<CreateOrderCommandHandler>(); // implements ICommandHandler<CreateOrderCommand, Order>
Defensive patterns

Strategy: validation

Validate before calling

// Before sending, verify a handler is registered:
var handlerType = typeof(ICommandHandler<,>).MakeGenericType(command.GetType(), typeof(TResult));
var hasHandler = serviceProvider.GetServices<Elsa.Mediator.Contracts.ICommandHandler>()
    .Any(h => handlerType.IsInstanceOfType(h));
if (!hasHandler)
    throw new InvalidOperationException($"No handler registered for {command.GetType().Name}; call AddCommandHandler<...>() first.");

Type guard

static bool HasHandler<TCommand, TResult>(IServiceProvider sp) =>
    sp.GetServices<Elsa.Mediator.Contracts.ICommandHandler>().Any(h =>
        h is Elsa.Mediator.Contracts.ICommandHandler<TCommand, TResult>);

Try / catch

try
{
    await mediator.SendAsync(command, cancellationToken);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("There is no handler to handle"))
{
    logger.LogError(ex, "Missing handler for {Command}", command.GetType().Name);
    throw;
}

Prevention

When it happens

Trigger: Calling IMediator.SendAsync (or ICommandSender) with a command type for which no class implementing ICommandHandler<ThatCommand, TResult> was registered in the service provider; registering the handler with a mismatched TResult so handlerType.IsInstanceOfType fails; forgetting to call AddCommandHandler<THandler>() / AddHandlersFrom<TAssembly>() during host configuration.

Common situations: Developers add a new command and handler but forget DI registration; handler registered for the wrong result type (e.g. ICommandHandler<MyCommand, Unit> vs ICommandHandler<MyCommand, MyResult>); handler registered in a different service collection than the one the mediator resolves from (test host vs app host); assembly scanning misses the handler's namespace; renaming a handler type breaks an explicit registration.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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

Appendix: source

Thrown at src/common/Elsa.Mediator/Middleware/Command/Components/CommandHandlerInvokerMiddleware.cs:30

/// </summary>
[UsedImplicitly]
public class CommandHandlerInvokerMiddleware(CommandMiddlewareDelegate next) : ICommandMiddleware
{
    /// <inheritdoc />
    [UnconditionalSuppressMessage("Trimming", "IL2060:Call to MakeGenericMethod can not be statically analyzed", Justification = "The result type is determined at runtime from command types and handlers are registered in DI.")]
    public async ValueTask InvokeAsync(CommandContext context)
    {
        // Find all handlers for the specified command.
        var command = context.Command;
        var commandType = command.GetType();
        var resultType = context.ResultType;
        var handlerType = typeof(ICommandHandler<,>).MakeGenericType(commandType, resultType);
        var serviceProvider = context.ServiceProvider;
        var commandHandlers = serviceProvider.GetServices<ICommandHandler>();
        var handlers = commandHandlers.DistinctBy(x => x.GetType()).Where(x => handlerType.IsInstanceOfType(x)).ToArray();

        if (handlers.Length == 0)
            throw new InvalidOperationException($"There is no handler to handle the {commandType.FullName} command");

        if (handlers.Length > 1)
            throw new InvalidOperationException($"Multiple handlers were found to handle the {commandType.FullName} command");

        var handler = handlers.First();
        var strategyContext = new CommandStrategyContext(context, handler, serviceProvider, context.CancellationToken);
        var strategy = context.CommandStrategy;
        var executeMethod = strategy.GetType().GetMethod(nameof(ICommandStrategy.ExecuteAsync))!;
        var executeMethodWithReturnType = executeMethod.MakeGenericMethod(resultType);

        // Execute command.
        var task = (Task)executeMethodWithReturnType.Invoke(strategy, [strategyContext])!;

        // Wait for completion.
        await task;

        // Get the result of the task.
        var taskWithReturnType = typeof(Task<>).MakeGenericType(resultType);

View on GitHub (pinned to fe9217bdfa)