LuckyPennySoftware/MediatR · error · InvalidOperationException

{implementationType.Name} must implement {typeof(IPipelineBe

Error message

{implementationType.Name} must implement {typeof(IPipelineBehavior<,>).FullName}

What it means

AddBehavior(Type, ServiceLifetime) inspects the type via FindInterfacesThatClose(IPipelineBehavior<,>) and throws InvalidOperationException when none are found, so only valid closed pipeline behaviors are registered against IPipelineBehavior<TRequest,TResponse>.

Source

Thrown at src/MediatR/MicrosoftExtensionsDI/MediatrServiceConfiguration.cs:177

    /// <returns>This</returns>
    public MediatRServiceConfiguration AddBehavior<TImplementationType>(ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
    {
        return AddBehavior(typeof(TImplementationType), serviceLifetime);
    }

    /// <summary>
    /// Register a closed behavior type against all <see cref="IPipelineBehavior{TRequest,TResponse}"/> implementations
    /// </summary>
    /// <param name="implementationType">Closed behavior implementation type</param>
    /// <param name="serviceLifetime">Optional service lifetime, defaults to <see cref="ServiceLifetime.Transient"/>.</param>
    /// <returns>This</returns>
    public MediatRServiceConfiguration AddBehavior(Type implementationType, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
    {
        var implementedGenericInterfaces = implementationType.FindInterfacesThatClose(typeof(IPipelineBehavior<,>)).ToList();

        if (implementedGenericInterfaces.Count == 0)
        {
            throw new InvalidOperationException($"{implementationType.Name} must implement {typeof(IPipelineBehavior<,>).FullName}");
        }

        foreach (var implementedBehaviorType in implementedGenericInterfaces)
        {
            BehaviorsToRegister.Add(new ServiceDescriptor(implementedBehaviorType, implementationType, serviceLifetime));
        }

        return this;
    }

    /// <summary>
    /// Register a closed behavior type
    /// </summary>
    /// <param name="serviceType">Closed behavior interface type</param>
    /// <param name="implementationType">Closed behavior implementation type</param>
    /// <param name="serviceLifetime">Optional service lifetime, defaults to <see cref="ServiceLifetime.Transient"/>.</param>
    /// <returns>This</returns>
    public MediatRServiceConfiguration AddBehavior(Type serviceType, Type implementationType, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)

View on GitHub (pinned to 916ef1b3d6)

Solutions

  1. Ensure the type implements IPipelineBehavior<TRequest, TResponse>.
  2. For stream pipelines use AddStreamBehavior / IStreamPipelineBehavior<,>.
  3. For open-generic behaviors use AddOpenBehavior(typeof(Foo<,>)).

Example fix

// before
// LoggingBehavior implements IStreamPipelineBehavior<,>
configuration.AddBehavior(typeof(LoggingBehavior<,>));
// after
configuration.AddStreamBehavior(typeof(LoggingBehavior<,>));
Defensive patterns

Strategy: validation

Validate before calling

var closes = implementationType.FindInterfacesThatClose(typeof(IPipelineBehavior<,>)).ToList();
if (closes.Count == 0)
    throw new InvalidOperationException($"{implementationType.Name} is not a closed IPipelineBehavior<,>.");

Type guard

static bool IsClosedPipelineBehavior(Type t) =>
    t.FindInterfacesThatClose(typeof(IPipelineBehavior<,>)).Any();

Prevention

When it happens

Trigger: Passing a Type to AddBehavior that does not implement IPipelineBehavior<TRequest,TResponse> — e.g. an IStreamPipelineBehavior, a request pre/post-processor, or an unrelated class.

Common situations: Confusing request pipeline behaviors with stream pipeline behaviors; registering an open generic via AddBehavior instead of AddOpenBehavior; registering a class that only implements a marker interface.

Related errors


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