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
- Make the class a closed pre-processor: class MyProcessor : IRequestPreProcessor<MyRequest> and register typeof(MyProcessor).
- If the class is generic by design (handles any TRequest), use AddOpenRequestPreProcessor(typeof(MyProcessor<>)) instead.
- 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
- Use the closed API only for concrete, fully-specified types.
- For generic processors, prefer the AddOpen* variants.
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
- {openBehaviorType.Name} must implement {typeof(IRequestPrePr
- {openBehaviorType.Name} must implement {typeof(IStreamPipeli
- {implementationType.Name} must implement {typeof(IRequestPos
- {openBehaviorType.Name} must implement {typeof(IRequestPostP
- Error registering the generic type: {requestType.FullName}.
AI-assisted analysis of LuckyPennySoftware/MediatR@916ef1b3d6 (2026-08-13).
Data as JSON: /api/errors/729d8e0c973047af.
Report an issue: GitHub.