LuckyPennySoftware/MediatR · error · InvalidOperationException
{openBehaviorType.Name} must implement {typeof(IStreamPipeli
Error message
{openBehaviorType.Name} must implement {typeof(IStreamPipelineBehavior<,>).FullName} What it means
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.
Source
Thrown at src/MediatR/MicrosoftExtensionsDI/MediatrServiceConfiguration.cs:336
/// <summary>
/// Registers an open stream behavior type against the <see cref="IStreamPipelineBehavior{TRequest,TResponse}"/> open generic interface type
/// </summary>
/// <param name="openBehaviorType">An open generic stream behavior type</param>
/// <param name="serviceLifetime">Optional service lifetime, defaults to <see cref="ServiceLifetime.Transient"/>.</param>
/// <returns>This</returns>
public MediatRServiceConfiguration AddOpenStreamBehavior(Type openBehaviorType, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
{
if (!openBehaviorType.IsGenericType)
{
throw new InvalidOperationException($"{openBehaviorType.Name} must be generic");
}
var implementedGenericInterfaces = openBehaviorType.GetInterfaces().Where(i => i.IsGenericType).Select(i => i.GetGenericTypeDefinition());
var implementedOpenBehaviorInterfaces = new HashSet<Type>(implementedGenericInterfaces.Where(i => i == typeof(IStreamPipelineBehavior<,>)));
if (implementedOpenBehaviorInterfaces.Count == 0)
{
throw new InvalidOperationException($"{openBehaviorType.Name} must implement {typeof(IStreamPipelineBehavior<,>).FullName}");
}
foreach (var openBehaviorInterface in implementedOpenBehaviorInterfaces)
{
StreamBehaviorsToRegister.Add(new ServiceDescriptor(openBehaviorInterface, openBehaviorType, serviceLifetime));
}
return this;
}
/// <summary>
/// Register a closed request pre processor type
/// </summary>
/// <typeparam name="TServiceType">Closed request pre processor interface type</typeparam>
/// <typeparam name="TImplementationType">Closed request pre processor implementation type</typeparam>
/// <param name="serviceLifetime">Optional service lifetime, defaults to <see cref="ServiceLifetime.Transient"/>.</param>
/// <returns>This</returns>
public MediatRServiceConfiguration AddRequestPreProcessor<TServiceType, TImplementationType>(ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
View on GitHub (pinned to 916ef1b3d6)
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>.
Example fix
// before
cfg.AddOpenStreamBehavior(typeof(MyPipelineBehavior<,>)); // implements IPipelineBehavior<,>
// after
public class MyStreamBehavior<TRequest, TResponse>
: IStreamPipelineBehavior<TRequest, TResponse>
where TRequest : IStreamRequest<TResponse>
{
public IAsyncEnumerable<TResponse> Handle(
TRequest request, StreamHandlerDelegate<TResponse> next,
CancellationToken ct) => next(request, ct);
}
cfg.AddOpenStreamBehavior(typeof(MyStreamBehavior<,>)); Defensive patterns
Strategy: validation
Validate before calling
// Validate before registering the open stream behavior
static bool ImplementsOpenStreamBehavior(Type t) =>
t.IsGenericType &&
t.GetInterfaces()
.Where(i => i.IsGenericType)
.Select(i => i.GetGenericTypeDefinition())
.Any(i => i == typeof(IStreamPipelineBehavior<,>));
if (ImplementsOpenStreamBehavior(typeof(MyBehavior<,>)))
cfg.AddOpenStreamBehavior(typeof(MyBehavior<,>)); Type guard
static bool IsOpenStreamBehavior(Type t) =>
t.IsGenericType &&
t.GetInterfaces()
.Where(i => i.IsGenericType)
.Select(i => i.GetGenericTypeDefinition())
.Contains(typeof(IStreamPipelineBehavior<,>)); Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- {openBehaviorType.Name} must implement {typeof(IRequestPrePr
- {openBehaviorType.Name} must implement {typeof(IRequestPostP
- Error registering the generic type: {requestType.FullName}.
- Error registering the generic type: {requestType.FullName}.
- Error registering the generic type: {requestType.FullName}.
AI-assisted analysis of LuckyPennySoftware/MediatR@916ef1b3d6 (2026-08-13).
Data as JSON: /api/errors/f987db10969c73f8.
Report an issue: GitHub.