LuckyPennySoftware/MediatR · error · InvalidOperationException

{openBehaviorType.Name} must implement {typeof(IPipelineBeha

Error message

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

What it means

After confirming the type is generic, AddOpenBehavior reflects over its interfaces for the open-generic IPipelineBehavior<,> definition. If none matches, it throws InvalidOperationException so an open generic that closes a different contract cannot be registered as a request pipeline behavior.

Source

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

    /// <summary>
    /// Registers an open behavior type against the <see cref="IPipelineBehavior{TRequest,TResponse}"/> open generic interface type
    /// </summary>
    /// <param name="openBehaviorType">An open generic behavior type</param>
    /// <param name="serviceLifetime">Optional service lifetime, defaults to <see cref="ServiceLifetime.Transient"/>.</param>
    /// <returns>This</returns>
    public MediatRServiceConfiguration AddOpenBehavior(Type openBehaviorType, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
    {
        if (!openBehaviorType.IsGenericType)
        {
            throw new InvalidOperationException($"{openBehaviorType.Name} must be generic");
        }

        var implementedGenericInterfaces = openBehaviorType.GetInterfaces().Where(i => i.IsGenericType).Select(i => i.GetGenericTypeDefinition());
        var implementedOpenBehaviorInterfaces = new HashSet<Type>(implementedGenericInterfaces.Where(i => i == typeof(IPipelineBehavior<,>)));

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

        foreach (var openBehaviorInterface in implementedOpenBehaviorInterfaces)
        {
            BehaviorsToRegister.Add(new ServiceDescriptor(openBehaviorInterface, openBehaviorType, serviceLifetime));
        }

        return this;
    }

    /// <summary>
    /// Registers multiple open behavior types against the <see cref="IPipelineBehavior{TRequest,TResponse}"/> open generic interface type
    /// </summary>
    /// <param name="openBehaviorTypes">An open generic behavior type list includes multiple open generic behavior types.</param>
    /// <param name="serviceLifetime">Optional service lifetime, defaults to <see cref="ServiceLifetime.Transient"/>.</param>
    /// <returns>This</returns>
    public MediatRServiceConfiguration AddOpenBehaviors(IEnumerable<Type> openBehaviorTypes, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
    {

View on GitHub (pinned to 916ef1b3d6)

Solutions

  1. Confirm the type implements IPipelineBehavior<TRequest, TResponse> (open form).
  2. For stream pipelines use AddOpenStreamBehavior(typeof(Foo<,>)).
  3. For pre/post-processors use the corresponding AddOpen* methods.

Example fix

// before
// StreamLogging<,> implements IStreamPipelineBehavior<,>
configuration.AddOpenBehavior(typeof(StreamLogging<,>));
// after
configuration.AddOpenStreamBehavior(typeof(StreamLogging<,>));
Defensive patterns

Strategy: validation

Validate before calling

bool closes = openBehaviorType.GetInterfaces()
    .Where(i => i.IsGenericType).Select(i => i.GetGenericTypeDefinition())
    .Any(i => i == typeof(IPipelineBehavior<,>));
if (!closes) throw new InvalidOperationException($"{openBehaviorType.Name} does not close IPipelineBehavior<,>.");

Type guard

static bool IsOpenPipelineBehavior(Type t) =>
    t.IsGenericType && t.GetInterfaces().Where(i => i.IsGenericType)
        .Select(i => i.GetGenericTypeDefinition()).Any(i => i == typeof(IPipelineBehavior<,>));

Prevention

When it happens

Trigger: Passing an open-generic type to AddOpenBehavior that implements IStreamPipelineBehavior<,>, IRequestPreProcessor<>, IRequestPostProcessor<,>, or no behavior contract at all.

Common situations: Registering an open stream pipeline behavior through AddOpenBehavior instead of AddOpenStreamBehavior; registering a generic pre/post-processor through the wrong method.

Related errors


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