LuckyPennySoftware/MediatR · error · InvalidOperationException

{implementationType.Name} must implement {typeof(IRequestPre

Error message

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

What it means

Thrown by AddRequestPreProcessor when a closed (fully constructed) implementation type does not close IRequestPreProcessor<TRequest> for any TRequest. MediatR uses FindInterfacesThatClose to walk the type's interface graph (including base types) and requires at least one matching closed interface before it can register each as a ServiceDescriptor.

Source

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

    /// <param name="serviceLifetime">Optional service lifetime, defaults to <see cref="ServiceLifetime.Transient"/>.</param>
    /// <returns>This</returns>
    public MediatRServiceConfiguration AddRequestPreProcessor<TImplementationType>(
        ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
        => AddRequestPreProcessor(typeof(TImplementationType), serviceLifetime);

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

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

        foreach (var implementedPreProcessorType in implementedGenericInterfaces)
        {
            RequestPreProcessorsToRegister.Add(new ServiceDescriptor(implementedPreProcessorType, implementationType, serviceLifetime));
        }
        
        return this;
    }
    
    /// <summary>
    /// Registers an open request pre processor type against the <see cref="IRequestPreProcessor{TRequest}"/> open generic interface type
    /// </summary>
    /// <param name="openBehaviorType">An open generic request pre processor type</param>
    /// <param name="serviceLifetime">Optional service lifetime, defaults to <see cref="ServiceLifetime.Transient"/>.</param>
    /// <returns>This</returns>
    public MediatRServiceConfiguration AddOpenRequestPreProcessor(Type openBehaviorType, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
    {

View on GitHub (pinned to 916ef1b3d6)

Solutions

  1. Make the class a closed pre-processor: class MyProcessor : IRequestPreProcessor<MyRequest> and register typeof(MyProcessor).
  2. If the class is generic by design (handles any TRequest), use AddOpenRequestPreProcessor(typeof(MyProcessor<>)) instead.
  3. Double-check the interface is IRequestPreProcessor<> (single arity), not IRequestPostProcessor<,> or IPipelineBehavior<,>.

Example fix

// before
public class MyProcessor : IRequestPostProcessor<MyRequest, Unit> { ... }
cfg.AddRequestPreProcessor(typeof(MyProcessor));

// after
public class MyProcessor : IRequestPreProcessor<MyRequest>
{
    public Task Process(MyRequest request, CancellationToken ct) => Task.CompletedTask;
}
cfg.AddRequestPreProcessor(typeof(MyProcessor));
Defensive patterns

Strategy: validation

Validate before calling

static bool IsClosedPreProcessor(Type t) =>
    !t.IsGenericTypeDefinition &&
    t.FindInterfacesThatClose(typeof(IRequestPreProcessor<>)).Any();

if (IsClosedPreProcessor(typeof(MyProcessor)))
    cfg.AddRequestPreProcessor(typeof(MyProcessor));

Type guard

static bool IsClosedPreProcessor(Type t) =>
    t.IsConcrete() &&
    t.FindInterfacesThatClose(typeof(IRequestPreProcessor<>)).Any();

Prevention

When it happens

Trigger: Calling cfg.AddRequestPreProcessor(typeof(MyProcessor)) where MyProcessor implements IRequestPostProcessor<,>, IStreamRequestHandler, or nothing request-related; or passing a pre-processor whose TRequest is still an open type parameter (use AddOpenRequestPreProcessor for that).

Common situations: Passing an open generic class (still has <T>) into the closed API; mixing up pre- vs. post-processor interfaces; refactoring that drops the interface; copy-pasting a handler type into the processor registration.

Related errors


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