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
- Check that the inner app's IHost descriptor is added by the standard HostBuilder pipeline, not by custom DI code.
- Align Microsoft.Extensions.Hosting / Aspire.Hosting.Testing package versions across the test project.
- Inspect builder.Services for IHost descriptors before creating the app and remove/replace non-standard registrations.
- 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
- Do not replace or remove the standard IHost registration in test AppHosts.
- Keep Aspire.Hosting.Testing and Microsoft.Extensions.Hosting packages on aligned versions.
- Review custom DI code in AppHost Program.cs that touches typeof(IHost).
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
- Application did not register an implementation of
- A QueueServiceClient could not be configured. Ensure valid…
- An EventProcessorClient could not be configured. Ensure a…
- ArgumentNullException for parameter 'services' (services is…
- ArgumentNullException: hostBuilder
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)