{"record":{"id":"729d8e0c973047af","repo":"LuckyPennySoftware/MediatR","slug":"implementationtype-name-must-implement-typeof-i-729d8e","errorCode":null,"errorMessage":"{implementationType.Name} must implement {typeof(IRequestPreProcessor<>).FullName}","messagePattern":"(.+?) must implement (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/MediatR/MicrosoftExtensionsDI/MediatrServiceConfiguration.cs","lineNumber":393,"sourceCode":"    /// <param name=\"serviceLifetime\">Optional service lifetime, defaults to <see cref=\"ServiceLifetime.Transient\"/>.</param>\r\n    /// <returns>This</returns>\r\n    public MediatRServiceConfiguration AddRequestPreProcessor<TImplementationType>(\r\n        ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\r\n        => AddRequestPreProcessor(typeof(TImplementationType), serviceLifetime);\r\n\r\n    /// <summary>\r\n    /// Register a closed request pre processor type against all <see cref=\"IRequestPreProcessor{TRequest}\"/> implementations\r\n    /// </summary>\r\n    /// <param name=\"implementationType\">Closed request pre processor implementation type</param>\r\n    /// <param name=\"serviceLifetime\">Optional service lifetime, defaults to <see cref=\"ServiceLifetime.Transient\"/>.</param>\r\n    /// <returns>This</returns>\r\n    public MediatRServiceConfiguration AddRequestPreProcessor(Type implementationType, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\r\n    {\r\n        var implementedGenericInterfaces = implementationType.FindInterfacesThatClose(typeof(IRequestPreProcessor<>)).ToList();\r\n\r\n        if (implementedGenericInterfaces.Count == 0)\r\n        {\r\n            throw new InvalidOperationException($\"{implementationType.Name} must implement {typeof(IRequestPreProcessor<>).FullName}\");\r\n        }\r\n\r\n        foreach (var implementedPreProcessorType in implementedGenericInterfaces)\r\n        {\r\n            RequestPreProcessorsToRegister.Add(new ServiceDescriptor(implementedPreProcessorType, implementationType, serviceLifetime));\r\n        }\r\n        \r\n        return this;\r\n    }\r\n    \r\n    /// <summary>\r\n    /// Registers an open request pre processor type against the <see cref=\"IRequestPreProcessor{TRequest}\"/> open generic interface type\r\n    /// </summary>\r\n    /// <param name=\"openBehaviorType\">An open generic request pre processor type</param>\r\n    /// <param name=\"serviceLifetime\">Optional service lifetime, defaults to <see cref=\"ServiceLifetime.Transient\"/>.</param>\r\n    /// <returns>This</returns>\r\n    public MediatRServiceConfiguration AddOpenRequestPreProcessor(Type openBehaviorType, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\r\n    {\r","sourceCodeStart":375,"sourceCodeEnd":411,"githubUrl":"https://github.com/LuckyPennySoftware/MediatR/blob/916ef1b3d68ccdc96db8f914eaf1b32fc7db52c5/src/MediatR/MicrosoftExtensionsDI/MediatrServiceConfiguration.cs#L375-L411","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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<,>."],"exampleFix":"// before\npublic class MyProcessor : IRequestPostProcessor<MyRequest, Unit> { ... }\ncfg.AddRequestPreProcessor(typeof(MyProcessor));\n\n// after\npublic class MyProcessor : IRequestPreProcessor<MyRequest>\n{\n    public Task Process(MyRequest request, CancellationToken ct) => Task.CompletedTask;\n}\ncfg.AddRequestPreProcessor(typeof(MyProcessor));","handlingStrategy":"validation","validationCode":"static bool IsClosedPreProcessor(Type t) =>\n    !t.IsGenericTypeDefinition &&\n    t.FindInterfacesThatClose(typeof(IRequestPreProcessor<>)).Any();\n\nif (IsClosedPreProcessor(typeof(MyProcessor)))\n    cfg.AddRequestPreProcessor(typeof(MyProcessor));","typeGuard":"static bool IsClosedPreProcessor(Type t) =>\n    t.IsConcrete() &&\n    t.FindInterfacesThatClose(typeof(IRequestPreProcessor<>)).Any();","tryCatchPattern":null,"preventionTips":["Use the closed API only for concrete, fully-specified types.","For generic processors, prefer the AddOpen* variants."],"tags":["di-registration","pre-processor","configuration"],"backgroundTag":null,"analyzedSha":"916ef1b3d68ccdc96db8f914eaf1b32fc7db52c5","analyzedAt":"2026-08-13T17:57:04.476Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}