RicoSuter/NSwag · error · InvalidOperationException

The NSwag DI services are not registered: Call…

Error message

The NSwag DI services are not registered: Call NSwagServiceCollectionExtensions.AddSwaggerDocument() in ConfigureServices().

What it means

OpenApiDocumentMiddleware requires the NSwag-registered OpenApiDocumentProvider from DI, which is added by NSwagServiceCollectionExtensions.AddSwaggerDocument()/AddOpenApiDocument(). If it is missing, the constructor throws InvalidOperationException telling you to call AddSwaggerDocument() in ConfigureServices().

Solutions

  1. Call services.AddOpenApiDocument() or services.AddSwaggerDocument() in ConfigureServices/builder.Services.
  2. Confirm the middleware is used in the same application whose service provider was configured.
  3. Check package references: NSwag.AspNetCore must be referenced and its DI extension namespace imported (Microsoft.Extensions.DependencyInjection).

Example fix

// before
var app = builder.Build();
app.UseOpenApi();
// after
builder.Services.AddOpenApiDocument();
var app = builder.Build();
app.UseOpenApi();
Defensive patterns

Strategy: validation

Validate before calling

// before UseOpenApi
if (!builder.Services.Any(d => d.ServiceType == typeof(NSwag.AspNetCore.OpenApiDocumentProvider)))
    throw new InvalidOperationException("Missing AddOpenApiDocument()/AddSwaggerDocument() registration.");

Type guard

bool NswagServicesRegistered(IServiceProvider sp) => sp.GetService<NSwag.AspNetCore.OpenApiDocumentProvider>() != null;

Try / catch

try { app.UseOpenApi(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("NSwag DI services are not registered")) { logger.LogError(ex, "Add AddSwaggerDocument()/AddOpenApiDocument() in ConfigureServices"); throw; }

Prevention

When it happens

Trigger: Calling app.UseOpenApi()/UseSwagger() without first calling services.AddOpenApiDocument()/AddSwaggerDocument(), or registering the middleware in an app that shares no DI container with the one configured.

Common situations: Adding only the middleware package without wiring the DI services; moving UseOpenApi to a different host/app builder; forgetting ConfigureServices changes after refactoring.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.

Related errors


AI-assisted analysis of RicoSuter/NSwag@63daf8fcc3 (2026-09-14). Data as JSON: /api/errors/779e116b7d4c0541. Report an issue: GitHub.

Appendix: source

Thrown at src/NSwag.AspNetCore/Middlewares/OpenApiDocumentMiddleware.cs:47

        private readonly Dictionary<string, Tuple<string, ExceptionDispatchInfo, DateTimeOffset>> _documentsCache = [];

        /// <summary>Initializes a new instance of the <see cref="OpenApiDocumentMiddleware"/> class.</summary>
        /// <param name="nextDelegate">The next delegate.</param>
        /// <param name="serviceProvider">The service provider.</param>
        /// <param name="documentName">The document name.</param>
        /// <param name="path">The document path.</param>
        /// <param name="settings">The settings.</param>
        public OpenApiDocumentMiddleware(RequestDelegate nextDelegate, IServiceProvider serviceProvider, string documentName, string path, OpenApiDocumentMiddlewareSettings settings)
        {
            _nextDelegate = nextDelegate;

            _documentName = documentName;
            _path = path.StartsWith('/') ? path : '/' + path;

            _apiDescriptionGroupCollectionProvider = serviceProvider.GetService<IApiDescriptionGroupCollectionProvider>() ??
                throw new InvalidOperationException("API Explorer not registered in DI.");
            _documentProvider = serviceProvider.GetService<OpenApiDocumentProvider>() ??
                throw new InvalidOperationException("The NSwag DI services are not registered: Call " + nameof(NSwagServiceCollectionExtensions.AddSwaggerDocument) + "() in ConfigureServices().");

            _settings = settings;
        }

        /// <summary>Invokes the specified context.</summary>
        /// <param name="context">The context.</param>
        /// <returns>The task.</returns>
        public async Task Invoke(HttpContext context)
        {
            if (context.Request.Path.HasValue && string.Equals(context.Request.Path.Value, _path, StringComparison.OrdinalIgnoreCase))
            {
                var schemaJson = await GetDocumentAsync(context);
                context.Response.StatusCode = 200;
                context.Response.Headers["Content-Type"] = _path.Contains(".yaml", StringComparison.OrdinalIgnoreCase) ?
                    "application/yaml; charset=utf-8" :
                    "application/json; charset=utf-8";

                await context.Response.WriteAsync(schemaJson);

View on GitHub (pinned to 63daf8fcc3)