LuckyPennySoftware/MediatR · error · InvalidOperationException

{openBehaviorType.Name} must be generic

Error message

{openBehaviorType.Name} must be generic

What it means

AddOpenBehavior requires an open-generic type so the DI container can close it per request. The first guard checks openBehaviorType.IsGenericType and throws InvalidOperationException if false, failing fast before reflection over generic-interface definitions would be meaningless.

Source

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

    /// <returns>This</returns>
    public MediatRServiceConfiguration AddBehavior(Type serviceType, Type implementationType, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
    {
        BehaviorsToRegister.Add(new ServiceDescriptor(serviceType, implementationType, serviceLifetime));

        return this;
    }

    /// <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;
    }

View on GitHub (pinned to 916ef1b3d6)

Solutions

  1. If the behavior is closed, use AddBehavior(typeof(ClosedBehavior)).
  2. If it is genuinely open-generic, pass the open form typeof(Foo<,>) (with unbound type parameters).
  3. Double-check the type has unbound generic arguments before registering.

Example fix

// before
configuration.AddOpenBehavior(typeof(ValidationBehavior<MyRequest, MyResponse>)); // closed
// after
configuration.AddOpenBehavior(typeof(ValidationBehavior<,>));              // open
// or for closed:
configuration.AddBehavior(typeof(ValidationBehavior<MyRequest, MyResponse>));
Defensive patterns

Strategy: validation

Validate before calling

if (!openBehaviorType.IsGenericType)
    throw new InvalidOperationException($"{openBehaviorType.Name} is not generic; use AddBehavior for closed behaviors.");

Type guard

static bool IsOpenGeneric(Type t) => t.IsGenericType && t.ContainsGenericParameters;

Prevention

When it happens

Trigger: Calling AddOpenBehavior(typeof(SomeClosedBehavior)) or AddOpenBehavior(typeof(NonGenericClass)) — any Type whose IsGenericType is false.

Common situations: Passing a closed behavior to AddOpenBehavior by mistake (should use AddBehavior); passing a concrete non-generic class; passing an unbound generic that was prematurely closed.

Related errors


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