{"record":{"id":"f987db10969c73f8","repo":"LuckyPennySoftware/MediatR","slug":"openbehaviortype-name-must-implement-typeof-ist","errorCode":null,"errorMessage":"{openBehaviorType.Name} must implement {typeof(IStreamPipelineBehavior<,>).FullName}","messagePattern":"(.+?) must implement (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/MediatR/MicrosoftExtensionsDI/MediatrServiceConfiguration.cs","lineNumber":336,"sourceCode":"    /// <summary>\r\n    /// Registers an open stream behavior type against the <see cref=\"IStreamPipelineBehavior{TRequest,TResponse}\"/> open generic interface type\r\n    /// </summary>\r\n    /// <param name=\"openBehaviorType\">An open generic stream behavior 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 AddOpenStreamBehavior(Type openBehaviorType, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\r\n    {\r\n        if (!openBehaviorType.IsGenericType)\r\n        {\r\n            throw new InvalidOperationException($\"{openBehaviorType.Name} must be generic\");\r\n        }\r\n\r\n        var implementedGenericInterfaces = openBehaviorType.GetInterfaces().Where(i => i.IsGenericType).Select(i => i.GetGenericTypeDefinition());\r\n        var implementedOpenBehaviorInterfaces = new HashSet<Type>(implementedGenericInterfaces.Where(i => i == typeof(IStreamPipelineBehavior<,>)));\r\n\r\n        if (implementedOpenBehaviorInterfaces.Count == 0)\r\n        {\r\n            throw new InvalidOperationException($\"{openBehaviorType.Name} must implement {typeof(IStreamPipelineBehavior<,>).FullName}\");\r\n        }\r\n\r\n        foreach (var openBehaviorInterface in implementedOpenBehaviorInterfaces)\r\n        {\r\n            StreamBehaviorsToRegister.Add(new ServiceDescriptor(openBehaviorInterface, openBehaviorType, serviceLifetime));\r\n        }\r\n\r\n        return this;\r\n    }\r\n\r\n    /// <summary>\r\n    /// Register a closed request pre processor type\r\n    /// </summary>\r\n    /// <typeparam name=\"TServiceType\">Closed request pre processor interface type</typeparam>\r\n    /// <typeparam name=\"TImplementationType\">Closed request pre 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 AddRequestPreProcessor<TServiceType, TImplementationType>(ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\r","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/LuckyPennySoftware/MediatR/blob/916ef1b3d68ccdc96db8f914eaf1b32fc7db52c5/src/MediatR/MicrosoftExtensionsDI/MediatrServiceConfiguration.cs#L318-L354","documentation":"Thrown by AddOpenStreamBehavior when the supplied open generic type does not implement IStreamPipelineBehavior<TRequest,TResponse>. MediatR scans the type's implemented generic interfaces (via GetInterfaces().GetGenericTypeDefinition()) and requires at least one to equal the open IStreamPipelineBehavior<,> definition so it can register it as a streaming pipeline behavior ServiceDescriptor.","triggerScenarios":"Calling services.AddMediatR(cfg => cfg.AddOpenStreamBehavior(typeof(SomeOpenGeneric))) where SomeOpenGeneric is generic but implements IPipelineBehavior<,> (the non-stream behavior) instead of IStreamPipelineBehavior<,>, or implements no pipeline interface at all.","commonSituations":"Confusing the stream vs. non-stream pipeline behaviors; passing a regular request behavior type into the stream registration API; copying a type name from a non-streaming sample; renaming/refactoring a behavior so it no longer declares the stream interface.","solutions":["Make the open generic type implement IStreamPipelineBehavior<TRequest,TResponse> where TRequest and TResponse are the open type parameters (e.g. class MyBehavior<TRequest,TResponse> : IStreamPipelineBehavior<TRequest,TResponse>).","If the type is actually a non-streaming behavior, register it with AddOpenBehavior (IPipelineBehavior<,>) instead of AddOpenStreamBehavior.","Verify the interface spelling and arity: stream behavior is the two-arity IStreamPipelineBehavior<TRequest,TResponse> and its Handle returns IAsyncEnumerable<TResponse>."],"exampleFix":"// before\ncfg.AddOpenStreamBehavior(typeof(MyPipelineBehavior<,>)); // implements IPipelineBehavior<,>\n\n// after\npublic class MyStreamBehavior<TRequest, TResponse>\n    : IStreamPipelineBehavior<TRequest, TResponse>\n    where TRequest : IStreamRequest<TResponse>\n{\n    public IAsyncEnumerable<TResponse> Handle(\n        TRequest request, StreamHandlerDelegate<TResponse> next,\n        CancellationToken ct) => next(request, ct);\n}\n\ncfg.AddOpenStreamBehavior(typeof(MyStreamBehavior<,>));","handlingStrategy":"validation","validationCode":"// Validate before registering the open stream behavior\nstatic bool ImplementsOpenStreamBehavior(Type t) =>\n    t.IsGenericType &&\n    t.GetInterfaces()\n        .Where(i => i.IsGenericType)\n        .Select(i => i.GetGenericTypeDefinition())\n        .Any(i => i == typeof(IStreamPipelineBehavior<,>));\n\nif (ImplementsOpenStreamBehavior(typeof(MyBehavior<,>)))\n    cfg.AddOpenStreamBehavior(typeof(MyBehavior<,>));","typeGuard":"static bool IsOpenStreamBehavior(Type t) =>\n    t.IsGenericType &&\n    t.GetInterfaces()\n        .Where(i => i.IsGenericType)\n        .Select(i => i.GetGenericTypeDefinition())\n        .Contains(typeof(IStreamPipelineBehavior<,>));","tryCatchPattern":null,"preventionTips":["Keep stream behaviors (IStreamPipelineBehavior<,>) visually distinct from non-stream behaviors (IPipelineBehavior<,>) in naming.","Add a startup smoke test that asserts every registered open behavior resolves."],"tags":["di-registration","stream-pipeline","open-generic","configuration"],"backgroundTag":null,"analyzedSha":"916ef1b3d68ccdc96db8f914eaf1b32fc7db52c5","analyzedAt":"2026-08-13T17:57:04.476Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}