dotnet/yarp · error · ArgumentException

TConsumer must implement at least one IMetricsConsumer inter

Error message

TConsumer must implement at least one IMetricsConsumer interface.

What it means

The generic AddMetricsConsumer<TConsumer>() uses IsAssignableFrom to detect each closed IMetricsConsumer<TMetrics> interface on TConsumer and register a forwarding factory. With no generic constraint, a TConsumer that implements none triggers ArgumentException(paramName: TConsumer) at startup.

Source

Thrown at src/TelemetryConsumption/TelemetryConsumptionExtensions.cs:248

            services.AddSingleton(services => (IMetricsConsumer<NameResolutionMetrics>)services.GetRequiredService<TConsumer>());
            implementsAny = true;
        }

        if (typeof(IMetricsConsumer<NetSecurityMetrics>).IsAssignableFrom(typeof(TConsumer)))
        {
            services.AddSingleton(services => (IMetricsConsumer<NetSecurityMetrics>)services.GetRequiredService<TConsumer>());
            implementsAny = true;
        }

        if (typeof(IMetricsConsumer<SocketsMetrics>).IsAssignableFrom(typeof(TConsumer)))
        {
            services.AddSingleton(services => (IMetricsConsumer<SocketsMetrics>)services.GetRequiredService<TConsumer>());
            implementsAny = true;
        }

        if (!implementsAny)
        {
            throw new ArgumentException("TConsumer must implement at least one IMetricsConsumer interface.", nameof(TConsumer));
        }

        services.TryAddSingleton<TConsumer>();

        services.AddTelemetryListeners();

        return services;
    }
}

View on GitHub (pinned to bd11867bee)

Solutions

  1. Implement at least one IMetricsConsumer<TMetrics> interface on TConsumer.
  2. If the type handles telemetry events, switch to AddTelemetryConsumer<TConsumer>().
  3. Add a compile-time `where TConsumer : IMetricsConsumer<HttpClientMetrics>` constraint on a wrapper to force a build error instead.

Example fix

// before
public class MyConsumer { ... }
services.AddMetricsConsumer<MyConsumer>();

// after
public class MyConsumer : IMetricsConsumer<SocketsMetrics> { ... }
services.AddMetricsConsumer<MyConsumer>();
Defensive patterns

Strategy: type-guard

Validate before calling

static bool ImplementsAnyMetricsConsumer<T>() =>
    typeof(IMetricsConsumer<HttpClientMetrics>).IsAssignableFrom(typeof(T))
    || typeof(IMetricsConsumer<SocketsMetrics>).IsAssignableFrom(typeof(T))
    || typeof(IMetricsConsumer<NetSecurityMetrics>).IsAssignableFrom(typeof(T));

if (ImplementsAnyMetricsConsumer<MyConsumer>())
    services.AddMetricsConsumer<MyConsumer>();

Type guard

public static IServiceCollection AddMyMetricsConsumer<TConsumer>(this IServiceCollection services)
    where TConsumer : class, IMetricsConsumer<HttpClientMetrics>
    => services.AddMetricsConsumer<TConsumer>();

Prevention

When it happens

Trigger: Calling services.AddMetricsConsumer<MyClass>() where MyClass implements no IMetricsConsumer<...> interface.

Common situations: Forgetting the interface on the consumer; version change that renamed/removed a metrics type so IsAssignableFrom no longer matches; passing a telemetry-only type to the metrics generic overload.

Related errors


AI-assisted analysis of dotnet/yarp@bd11867bee (2026-08-13). Data as JSON: /api/errors/d172b1cf60930d1e. Report an issue: GitHub.