microsoft/aspire · error · InvalidOperationException

Registered service descriptor for

Error message

Registered service descriptor for {typeof(IHost)} does not conform to any known pattern.

What it means

DistributedApplicationFactory intercepts the IHost registration that the inner test app adds, re-keying it on the factory instance so it can observe host creation. The IHost ServiceDescriptor must supply one of ImplementationFactory, ImplementationInstance, or ImplementationType; if it supplies none, the factory cannot re-key it and throws this error. This is an internal invariant violation: it means the hosting/test infrastructure changed its IHost registration shape.

Solutions

  1. Check that the inner app's IHost descriptor is added by the standard HostBuilder pipeline, not by custom DI code.
  2. Align Microsoft.Extensions.Hosting / Aspire.Hosting.Testing package versions across the test project.
  3. Inspect builder.Services for IHost descriptors before creating the app and remove/replace non-standard registrations.
  4. Report to Aspire if caused by an infrastructure change, since it indicates an unrecognized registration pattern.

Example fix

// before (custom descriptor without implementation)
builder.Services.Add(new ServiceDescriptor(typeof(IHost), (IHost)null!));
// after (supply an implementation factory)
builder.Services.Add(ServiceDescriptor.Singleton<IHost>(sp => sp.BuildHost()));
Defensive patterns

Strategy: try-catch

Validate before calling

var descriptors = appBuilder.Services.Where(d => d.ServiceType == typeof(IHost)).ToList();
if (descriptors.Any(d => d.ImplementationFactory is null && d.ImplementationInstance is null && d.ImplementationType is null))
{
    throw new InvalidOperationException("IHost descriptor has no implementation; DistributedApplicationFactory cannot intercept it.");
}

Type guard

static bool HasUsableIHostDescriptor(IServiceProvider sp) =>
    sp.GetRequiredService<IServiceCollection>() is var s &&
    s.Where(d => d.ServiceType == typeof(IHost)).All(d =>
        d.ImplementationFactory is not null || d.ImplementationInstance is not null || d.ImplementationType is not null);

Try / catch

try
{
    var app = await DistributedApplicationTesting.CreateAsync<Program>();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("does not conform to any known pattern"))
{
    // IHost registration was replaced by non-standard DI code; inspect builder.Services.
}

Prevention

When it happens

Trigger: Calling CreateAsync/StartAsync on a DistributedApplicationFactory (or DistributedApplicationTesting.CreateAsync) when the application's IHost service descriptor in DI has no implementation factory, instance, or type — typically from custom test-host wiring or a mismatched Microsoft.Extensions.Hosting version replacing the standard registration.

Common situations: Custom test scaffolding that pre-registers IHost with an empty/odd descriptor; package version skew between Aspire.Hosting.Testing and Microsoft.Extensions.Hosting after upgrades; code that replaces or removes the default IHost registration before the factory builds.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/ef6a2f8b68d2ba30. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Testing/DistributedApplicationFactory.cs:549

                // Ignore during disposal.
            }
        }
    }

    // Replaces the IHost registration with an InterceptedHost registration which delegates to the original registration.
    private void InterceptHostCreation(DistributedApplicationBuilder applicationBuilder)
    {
        // Find the original IHost registration and remove it.
        var hostDescriptor = applicationBuilder.Services.Single(s => s.ServiceType == typeof(IHost) && s.ServiceKey is null);
        applicationBuilder.Services.Remove(hostDescriptor);

        // Insert the registration, modified to be a keyed service keyed on this factory instance.
        var interceptedDescriptor = hostDescriptor switch
        {
            { ImplementationFactory: { } factory } => ServiceDescriptor.KeyedSingleton<IHost>(this, (sp, _) => (IHost)factory(sp)),
            { ImplementationInstance: { } instance } => ServiceDescriptor.KeyedSingleton<IHost>(this, (IHost)instance),
            { ImplementationType: { } type } => ServiceDescriptor.KeyedSingleton(typeof(IHost), this, type),
            _ => throw new InvalidOperationException($"Registered service descriptor for {typeof(IHost)} does not conform to any known pattern.")
        };
        applicationBuilder.Services.Add(interceptedDescriptor);

        // Add a non-keyed registration which resolved the keyed registration, enabling interception.
        applicationBuilder.Services.AddSingleton<IHost>(sp => new ObservedHost(sp.GetRequiredKeyedService<IHost>(this), this));
    }

    private sealed class ObservedHost(IHost innerHost, DistributedApplicationFactory appFactory) : IHost, IAsyncDisposable
    {
        private bool _disposing;

        public IServiceProvider Services => innerHost.Services;

        public void Dispose()
        {
            if (_disposing)
            {
                return;

View on GitHub (pinned to 25830f84bd)