LuckyPennySoftware/MediatR · error · InvalidOperationException

{implementationType.Name} must implement {typeof(IRequestPos

Error message

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

What it means

Thrown by AddRequestPostProcessor when a closed implementation type does not close IRequestPostProcessor<TRequest,TResponse> for any pair. FindInterfacesThatClose walks the type graph and finds no matching closed interface, so no ServiceDescriptor can be created.

Source

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

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

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

        foreach (var implementedPostProcessorType in implementedGenericInterfaces)
        {
            RequestPostProcessorsToRegister.Add(new ServiceDescriptor(implementedPostProcessorType, implementationType, serviceLifetime));
        }
        return this;
    }
    
    /// <summary>
    /// Registers an open request post processor type against the <see cref="IRequestPostProcessor{TRequest,TResponse}"/> open generic interface type
    /// </summary>
    /// <param name="openBehaviorType">An open generic request post processor type</param>
    /// <param name="serviceLifetime">Optional service lifetime, defaults to <see cref="ServiceLifetime.Transient"/>.</param>
    /// <returns>This</returns>
    public MediatRServiceConfiguration AddOpenRequestPostProcessor(Type openBehaviorType, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
    {
        if (!openBehaviorType.IsGenericType)

View on GitHub (pinned to 916ef1b3d6)

Solutions

  1. Make the class a closed post-processor: class MyProcessor : IRequestPostProcessor<MyRequest, MyResponse>.
  2. If the class is generic across request/response, use AddOpenRequestPostProcessor(typeof(MyProcessor<,>)).
  3. Verify arity: post-processor is IRequestPostProcessor<TRequest,TResponse> (two parameters).

Example fix

// before
public class MyProcessor : IRequestPreProcessor<MyRequest> { ... }
cfg.AddRequestPostProcessor(typeof(MyProcessor));

// after
public class MyProcessor : IRequestPostProcessor<MyRequest, MyResponse>
{
    public Task Process(MyRequest req, MyResponse resp, CancellationToken ct)
        => Task.CompletedTask;
}
cfg.AddRequestPostProcessor(typeof(MyProcessor));
Defensive patterns

Strategy: validation

Validate before calling

static bool IsClosedPostProcessor(Type t) =>
    t.IsConcrete() &&
    t.FindInterfacesThatClose(typeof(IRequestPostProcessor<,>)).Any();

if (IsClosedPostProcessor(typeof(MyProcessor)))
    cfg.AddRequestPostProcessor(typeof(MyProcessor));

Type guard

static bool IsClosedPostProcessor(Type t) =>
    t.IsConcrete() &&
    t.FindInterfacesThatClose(typeof(IRequestPostProcessor<,>)).Any();

Prevention

When it happens

Trigger: Calling cfg.AddRequestPostProcessor(typeof(MyProcessor)) where MyProcessor implements IRequestPreProcessor<> (wrong arity/direction) or no processor interface; passing an open generic type into this closed API.

Common situations: Confusing pre- and post-processors; passing an open generic class (use AddOpenRequestPostProcessor); refactoring that removes the interface.

Related errors


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