Start Debugging

Fix: The 'interceptors' feature is not enabled in this namespace

CS9137 comes from the Microsoft.AspNetCore.OpenApi source generator. Add InterceptorsNamespaces to every project that calls AddOpenApi, not just the one holding the PackageReference.

Add this to the project the compiler names in the error, not to the project that owns the PackageReference:

<!-- .NET 10 / .NET 11, Microsoft.AspNetCore.OpenApi 10.0.x -->
<PropertyGroup>
  <InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.AspNetCore.OpenApi.Generated</InterceptorsNamespaces>
</PropertyGroup>

The XML comment source generator inside Microsoft.AspNetCore.OpenApi emits interceptors, and the MSBuild property that whitelists their namespace ships in the package’s build/ folder. NuGet does not flow build/ across a ProjectReference or a transitive package dependency, but it does flow analyzers. So any project that inherits the generator without inheriting the property fails to compile. Everything below is verified against SDK 10.0.201 and Microsoft.AspNetCore.OpenApi 10.0.10.

The error in context

The compiler points at a file you never wrote, inside obj:

obj\Debug\net10.0\Microsoft.AspNetCore.OpenApi.SourceGenerators\Microsoft.AspNetCore.OpenApi.SourceGenerators.XmlCommentGenerator\OpenApiXmlCommentSupport.generated.cs(598,10):
error CS9137: The 'interceptors' feature is not enabled in this namespace. Add '<InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.AspNetCore.OpenApi.Generated</InterceptorsNamespaces>' to your project.

CS9137 comes with a namespace attached, and that namespace tells you which generator is upset:

Namespace in the messageGenerator
Microsoft.AspNetCore.OpenApi.GeneratedOpenAPI XML documentation comments
Microsoft.Extensions.Validation.GeneratedMinimal API validation (.NET 10 and later)
Microsoft.AspNetCore.Http.Validation.GeneratedSame generator, the .NET 10 preview name
Microsoft.AspNetCore.Http.GeneratedRequest delegate generator (Native AOT minimal APIs)
Microsoft.Extensions.Configuration.Binder.SourceGenerationConfiguration binder generator

Only the first one is your problem to solve by hand on a released SDK. The other three are already handled by the .NET SDK itself, in Microsoft.NET.Sdk.FrameworkReferenceResolution.targets:

<!-- SDK 10.0.201, Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets -->
<InterceptorsPreviewNamespaces Condition="'$(EnableRequestDelegateGenerator)' == 'true'">$(InterceptorsPreviewNamespaces);Microsoft.AspNetCore.Http.Generated</InterceptorsPreviewNamespaces>
<InterceptorsPreviewNamespaces Condition="'$(EnableConfigurationBindingGenerator)' == 'true'">$(InterceptorsPreviewNamespaces);Microsoft.Extensions.Configuration.Binder.SourceGeneration</InterceptorsPreviewNamespaces>
<InterceptorsPreviewNamespaces Condition="'$(_TargetFrameworkVersionWithoutV)' != '' and $([MSBuild]::VersionGreaterThanOrEquals('$(_TargetFrameworkVersionWithoutV)', '10.0'))">$(InterceptorsPreviewNamespaces);Microsoft.Extensions.Validation.Generated</InterceptorsPreviewNamespaces>

If you are still seeing the Microsoft.AspNetCore.Http.Validation.Generated spelling, you are on a .NET 10 preview SDK. The namespace was renamed before release, so a fix copied from a 2025 blog post is now a no-op string.

Why this happens

Interceptors are opt-in per namespace. Roslyn will not accept an [InterceptsLocation] attribute unless the containing namespace was passed to the compiler through /features:InterceptorsNamespaces, and MSBuild builds that switch from two properties, both forwarded in Microsoft.CSharp.Core.targets:

<!-- SDK 10.0.201, Roslyn/Microsoft.CSharp.Core.targets -->
InterceptorsNamespaces="$(InterceptorsNamespaces)"
InterceptorsPreviewNamespaces="$(InterceptorsPreviewNamespaces)"

The OpenAPI XML comment generator has been emitting interceptors since .NET 10. Turn on EmitCompilerGeneratedFiles and you can read exactly what it produces:

// Generated by Microsoft.AspNetCore.OpenApi.SourceGenerators 10.0.10
namespace Microsoft.AspNetCore.OpenApi.Generated
{
    file static class GeneratedServiceCollectionExtensions
    {
        [global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "iPD7FWRAJiLeb9V88cfKbz0BAABDbGFzczEuY3M=")]
        public static IServiceCollection AddOpenApi(this IServiceCollection services, string documentName)
        {
            return services.AddOpenApi(documentName, options =>
            {
                options.AddSchemaTransformer(new XmlCommentSchemaTransformer());
                options.AddOperationTransformer(new XmlCommentOperationTransformer());
            });
        }
    }
}

That is the whole feature: your AddOpenApi() call site is rewritten at compile time into one that also registers the two transformers carrying your XML comments. Nothing about it is optional or lazy, which is why a namespace that is not whitelisted is a hard build error rather than a warning.

The package enables the namespace for you, in a single file:

<!-- microsoft.aspnetcore.openapi/10.0.10/build/Microsoft.AspNetCore.OpenApi.targets -->
<Project>
  <PropertyGroup>
    <InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.AspNetCore.OpenApi.Generated</InterceptorsNamespaces>
  </PropertyGroup>
  <Target Name="GenerateAdditionalXmlFilesForOpenApi" AfterTargets="ResolveReferences">
    ...
  </Target>
</Project>

Note the folder: build, not buildTransitive. That is the asymmetry the whole error rests on. In ASP.NET Core’s own packaging, the line is explicit:

<!-- dotnet/aspnetcore, src/OpenApi/src/Microsoft.AspNetCore.OpenApi.csproj -->
<None Include="..\build\Microsoft.AspNetCore.OpenApi.targets" Pack="true" PackagePath="build" Visible="false" />

NuGet only flows buildTransitive/ assets to indirect consumers. Analyzers, on the other hand, do flow. A project that picks up Microsoft.AspNetCore.OpenApi through a ProjectReference therefore gets the source generator and none of the MSBuild plumbing that makes its output legal. Cause and cure are in different projects, which is why the error reads as nonsense the first time: you already added the property, just not in the project the compiler is complaining about.

One command tells you which side of the line a project is on:

dotnet msbuild MyApi.csproj -getProperty:InterceptorsNamespaces

An empty value means the property never arrived. ;Microsoft.AspNetCore.OpenApi.Generated means it did.

Minimal repro

Two projects. The first has the package, the second only references the first:

<!-- Defaults.csproj -- .NET 10, Microsoft.AspNetCore.OpenApi 10.0.10 -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.10" />
  </ItemGroup>
</Project>
<!-- Modules.csproj -- .NET 10, no PackageReference of its own -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\Defaults\Defaults.csproj" />
  </ItemGroup>
</Project>

Both call AddOpenApi:

// Modules/Class1.cs -- .NET 10, C# 14
using Microsoft.Extensions.DependencyInjection;

namespace Modules;

/// <summary>Module registrations.</summary>
public static class ModuleExtensions
{
    /// <summary>Adds the module's OpenAPI document.</summary>
    public static IServiceCollection AddModule(this IServiceCollection services)
        => services.AddOpenApi("module");
}

dotnet build Defaults succeeds. dotnet build Modules fails with CS9137. The shape is the same whether the downstream project uses Microsoft.NET.Sdk or Microsoft.NET.Sdk.Web: I reproduced it with a plain dotnet new web API whose only path to the package was a ProjectReference to a shared defaults library. Being a web project buys you nothing here.

Real codebases hit this in three recognisable shapes: an Aspire style ServiceDefaults library that centralises AddOpenApi, a modular monolith where each module registers its own document, and a plugin or CMS host (Umbraco and OrchardCore modules both show up in the issue reports) where the package sits in a base package one level up.

The fix, in order of preference

1. Add the property to the failing project

Copy the namespace out of the error message and paste the property into the .csproj the error names:

<!-- .NET 10 / .NET 11, Microsoft.AspNetCore.OpenApi 10.0.x -->
<PropertyGroup>
  <InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.AspNetCore.OpenApi.Generated</InterceptorsNamespaces>
</PropertyGroup>

Keep the leading $(InterceptorsNamespaces);. Other generators append to the same property, and a bare assignment throws their entries away. This keeps the generator running, so XML comments still reach the document.

If several projects in a solution register documents, put it once in Directory.Build.props instead of repeating it. The package targets are imported after the project body and append to whatever they find, so the two never fight.

2. Give the project its own PackageReference

If the project genuinely calls AddOpenApi, it has a legitimate claim to the package:

dotnet add Modules package Microsoft.AspNetCore.OpenApi

That pulls in build/Microsoft.AspNetCore.OpenApi.targets, which sets the property for you. I verified this clears the error with no other change. It is more honest than the transitive arrangement, and it survives someone later reshuffling project references.

3. Turn the generator off in that project

If the project has no interest in XML comments, remove the analyzer instead of whitelisting its output. The official documentation shows this with the package path property; the item-based form is less brittle:

<!-- .NET 10, disables the OpenAPI XML comment generator for this project only -->
<Target Name="DisableOpenApiXmlGenerator" BeforeTargets="CoreCompile">
  <ItemGroup>
    <Analyzer Remove="@(Analyzer)"
              Condition="'%(Filename)' == 'Microsoft.AspNetCore.OpenApi.SourceGenerators'" />
  </ItemGroup>
</Target>

The build goes green, and the cost is that <summary> and <param> text no longer appears in that project’s OpenAPI output. The same effect, applied from the other end, comes from PrivateAssets="analyzers" on the upstream PackageReference, which stops the generator reaching any consumer of that library:

<!-- Defaults.csproj -- .NET 10, keeps the generator out of downstream projects -->
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.10" PrivateAssets="analyzers" />

Both are verified fixes. Reach for them when a build server is red and you need the pipeline back before you need the documentation.

Gotchas that keep the build red

InterceptorsPreviewNamespaces still works, and is not the modern spelling. The old property is honoured by the C# 14 compiler in SDK 10.0.201, warning free, and the SDK still uses it for its own three namespaces. Use InterceptorsNamespaces in new code, but do not “fix” an inherited build by renaming a working property.

Turning off XML documentation does not turn off the generator. Setting <GenerateDocumentationFile>false</GenerateDocumentationFile> feels like it should sidestep an XML comment generator. It does not. The generator still intercepts AddOpenApi, and the same CS9137 comes back at line 597 instead of 598. If you want it gone, remove the analyzer.

The interception is per call site, per compilation. This one costs people hours after the build is green. The transformers are baked into the compilation where the AddOpenApi() call physically appears, and they carry only that compilation’s XML comments. Move the call into a shared defaults library and your API project’s summaries silently vanish from the document. Measured on the repro above, with AddOpenApi() inlined in the API project:

{
  "summary": "Gets a single widget by id.",
  "parameters": [
    { "name": "id", "description": "The widget identifier." }
  ]
}

With the identical endpoint documented the same way, but AddOpenApi() called from the referenced library, both the summary and the parameter description are absent. Keep the AddOpenApi() call in the project whose comments you want, or feed the other assemblies’ XML files in through AdditionalFiles.

A non-literal document name is not intercepted. AddOpenApi(documentName) where documentName is a variable produces no interceptor at all, so you get no error and no XML comments. Only literal strings are matched.

EmitCompilerGeneratedFiles can create a second, worse error. Inspecting the generated file is the right instinct, but if you also point CompilerGeneratedFilesOutputPath at a folder inside the project directory, the emitted file becomes a real compilation input on the next build:

Generated\...\OpenApiXmlCommentSupport.generated.cs(67,42):
error CS0433: The type 'XmlComment' exists in both 'Api' and 'Api'

Leave the output path under obj, or add a matching <Compile Remove>.

Interceptors are not the LangVersion problem they look like. They have been legal since C# 12, so an explicit <LangVersion>12.0</LangVersion> compiles the generated file fine once the namespace is whitelisted. Do not go chasing language versions.

Check the whole graph, not the one project. Once you fix the project named in the error, the next project up the chain often fails the same way on the next build. dotnet msbuild <project> -getProperty:InterceptorsNamespaces across the solution finds them all in one pass.

The generator behind this error is the same machinery described in what a source generator is and when you need one, and the interceptor mechanism itself is covered in C# 12 interceptors. If you arrived here mid-upgrade, the other build break in this package family is the missing OpenApiReference type, and the wider move is in migrating from Swashbuckle to the built-in OpenAPI generator. Once the document builds, customizing it with operation and schema transformers is the next step, and serving it with Scalar puts a UI in front of it.

Sources

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Back