{"record":{"id":"5bb66363bb2cdb38","repo":"LuckyPennySoftware/MediatR","slug":"implementationtype-name-must-implement-typeof-i-5bb663","errorCode":null,"errorMessage":"{implementationType.Name} must implement {typeof(IRequestPostProcessor<,>).FullName}","messagePattern":"(.+?) must implement (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/MediatR/MicrosoftExtensionsDI/MediatrServiceConfiguration.cs","lineNumber":478,"sourceCode":"    /// <typeparam name=\"TImplementationType\">Closed request post processor implementation type</typeparam>\r\n    /// <param name=\"serviceLifetime\">Optional service lifetime, defaults to <see cref=\"ServiceLifetime.Transient\"/>.</param>\r\n    /// <returns>This</returns>\r\n    public MediatRServiceConfiguration AddRequestPostProcessor<TImplementationType>(ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\r\n        => AddRequestPostProcessor(typeof(TImplementationType), serviceLifetime);\r\n    \r\n    /// <summary>\r\n    /// Register a closed request post processor type against all <see cref=\"IRequestPostProcessor{TRequest,TResponse}\"/> implementations\r\n    /// </summary>\r\n    /// <param name=\"implementationType\">Closed request post 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 AddRequestPostProcessor(Type implementationType, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\r\n    {\r\n        var implementedGenericInterfaces = implementationType.FindInterfacesThatClose(typeof(IRequestPostProcessor<,>)).ToList();\r\n\r\n        if (implementedGenericInterfaces.Count == 0)\r\n        {\r\n            throw new InvalidOperationException($\"{implementationType.Name} must implement {typeof(IRequestPostProcessor<,>).FullName}\");\r\n        }\r\n\r\n        foreach (var implementedPostProcessorType in implementedGenericInterfaces)\r\n        {\r\n            RequestPostProcessorsToRegister.Add(new ServiceDescriptor(implementedPostProcessorType, implementationType, serviceLifetime));\r\n        }\r\n        return this;\r\n    }\r\n    \r\n    /// <summary>\r\n    /// Registers an open request post processor type against the <see cref=\"IRequestPostProcessor{TRequest,TResponse}\"/> open generic interface type\r\n    /// </summary>\r\n    /// <param name=\"openBehaviorType\">An open generic request post 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 AddOpenRequestPostProcessor(Type openBehaviorType, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\r\n    {\r\n        if (!openBehaviorType.IsGenericType)\r","sourceCodeStart":460,"sourceCodeEnd":496,"githubUrl":"https://github.com/LuckyPennySoftware/MediatR/blob/916ef1b3d68ccdc96db8f914eaf1b32fc7db52c5/src/MediatR/MicrosoftExtensionsDI/MediatrServiceConfiguration.cs#L460-L496","documentation":"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.","triggerScenarios":"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.","commonSituations":"Confusing pre- and post-processors; passing an open generic class (use AddOpenRequestPostProcessor); refactoring that removes the interface.","solutions":["Make the class a closed post-processor: class MyProcessor : IRequestPostProcessor<MyRequest, MyResponse>.","If the class is generic across request/response, use AddOpenRequestPostProcessor(typeof(MyProcessor<,>)).","Verify arity: post-processor is IRequestPostProcessor<TRequest,TResponse> (two parameters)."],"exampleFix":"// before\npublic class MyProcessor : IRequestPreProcessor<MyRequest> { ... }\ncfg.AddRequestPostProcessor(typeof(MyProcessor));\n\n// after\npublic class MyProcessor : IRequestPostProcessor<MyRequest, MyResponse>\n{\n    public Task Process(MyRequest req, MyResponse resp, CancellationToken ct)\n        => Task.CompletedTask;\n}\ncfg.AddRequestPostProcessor(typeof(MyProcessor));","handlingStrategy":"validation","validationCode":"static bool IsClosedPostProcessor(Type t) =>\n    t.IsConcrete() &&\n    t.FindInterfacesThatClose(typeof(IRequestPostProcessor<,>)).Any();\n\nif (IsClosedPostProcessor(typeof(MyProcessor)))\n    cfg.AddRequestPostProcessor(typeof(MyProcessor));","typeGuard":"static bool IsClosedPostProcessor(Type t) =>\n    t.IsConcrete() &&\n    t.FindInterfacesThatClose(typeof(IRequestPostProcessor<,>)).Any();","tryCatchPattern":null,"preventionTips":["Post-processors are two-arity (TRequest, TResponse); double-check before registering.","Keep pre- and post-processor classes in separate folders/namespaces."],"tags":["di-registration","post-processor","configuration"],"backgroundTag":null,"analyzedSha":"916ef1b3d68ccdc96db8f914eaf1b32fc7db52c5","analyzedAt":"2026-08-13T17:57:04.476Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}