Correção: The 'interceptors' feature is not enabled in this namespace
CS9137 vem do gerador de código-fonte do Microsoft.AspNetCore.OpenApi. Adicione InterceptorsNamespaces a todo projeto que chama AddOpenApi, não só ao que tem o PackageReference.
Adicione isto ao projeto que o compilador cita no erro, não ao projeto que tem o PackageReference:
<!-- .NET 10 / .NET 11, Microsoft.AspNetCore.OpenApi 10.0.x -->
<PropertyGroup>
<InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.AspNetCore.OpenApi.Generated</InterceptorsNamespaces>
</PropertyGroup>
O gerador de código-fonte de comentários XML dentro do Microsoft.AspNetCore.OpenApi emite interceptadores, e a propriedade do MSBuild que autoriza o namespace deles é distribuída na pasta build/ do pacote. O NuGet não propaga build/ através de um ProjectReference nem de uma dependência transitiva de pacote, mas propaga os analisadores. Por isso, qualquer projeto que herda o gerador sem herdar a propriedade falha ao compilar. Tudo abaixo foi verificado com o SDK 10.0.201 e o Microsoft.AspNetCore.OpenApi 10.0.10.
O erro em contexto
O compilador aponta para um arquivo que você nunca escreveu, dentro de 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.
O CS9137 sempre vem com um namespace anexado, e esse namespace diz qual gerador está insatisfeito:
| Namespace na mensagem | Gerador |
|---|---|
Microsoft.AspNetCore.OpenApi.Generated | Comentários de documentação XML para OpenAPI |
Microsoft.Extensions.Validation.Generated | Validação de minimal APIs (.NET 10 em diante) |
Microsoft.AspNetCore.Http.Validation.Generated | O mesmo gerador, com o nome da versão prévia do .NET 10 |
Microsoft.AspNetCore.Http.Generated | Request delegate generator (minimal APIs com Native AOT) |
Microsoft.Extensions.Configuration.Binder.SourceGeneration | Gerador do binder de configuração |
Só o primeiro é problema seu para resolver na mão em um SDK já lançado. Os outros três o próprio SDK do .NET resolve, em 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>
Se você ainda vê a grafia Microsoft.AspNetCore.Http.Validation.Generated, está em um SDK de versão prévia do .NET 10. O namespace foi renomeado antes do lançamento, então uma correção copiada de um artigo de 2025 hoje é apenas um texto sem efeito.
Por que isso acontece
Interceptadores são habilitados por namespace. O Roslyn não aceita um atributo [InterceptsLocation] a menos que o namespace que o contém tenha sido passado ao compilador via /features:InterceptorsNamespaces, e o MSBuild monta essa opção a partir de duas propriedades, ambas repassadas em Microsoft.CSharp.Core.targets:
<!-- SDK 10.0.201, Roslyn/Microsoft.CSharp.Core.targets -->
InterceptorsNamespaces="$(InterceptorsNamespaces)"
InterceptorsPreviewNamespaces="$(InterceptorsPreviewNamespaces)"
O gerador de comentários XML do OpenAPI emite interceptadores desde o .NET 10. Ative EmitCompilerGeneratedFiles e você consegue ler exatamente o que ele produz:
// 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());
});
}
}
}
É esse o recurso inteiro: o ponto de chamada do seu AddOpenApi() é reescrito em tempo de compilação para outro que também registra os dois transformadores que carregam seus comentários XML. Nada disso é opcional ou preguiçoso, e é por isso que um namespace não autorizado é um erro duro de compilação, não um aviso.
O pacote habilita o namespace para você, em um único arquivo:
<!-- 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>
Repare na pasta: build, não buildTransitive. Essa assimetria é a base de todo o erro. No empacotamento do próprio ASP.NET Core, a linha é explícita:
<!-- dotnet/aspnetcore, src/OpenApi/src/Microsoft.AspNetCore.OpenApi.csproj -->
<None Include="..\build\Microsoft.AspNetCore.OpenApi.targets" Pack="true" PackagePath="build" Visible="false" />
O NuGet só propaga recursos de buildTransitive/ para consumidores indiretos. Já os analisadores se propagam. Portanto, um projeto que recebe o Microsoft.AspNetCore.OpenApi por um ProjectReference ganha o gerador de código-fonte e nada da infraestrutura de MSBuild que torna a saída dele legal. Causa e cura ficam em projetos diferentes, e é por isso que o erro parece absurdo na primeira vez: você já adicionou a propriedade, só que não no projeto do qual o compilador reclama.
Um comando diz de que lado da linha um projeto está:
dotnet msbuild MyApi.csproj -getProperty:InterceptorsNamespaces
Valor vazio significa que a propriedade nunca chegou. ;Microsoft.AspNetCore.OpenApi.Generated significa que chegou.
Reprodução mínima
Dois projetos. O primeiro tem o pacote, o segundo apenas referencia o primeiro:
<!-- 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>
Os dois chamam 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 compila. dotnet build Modules falha com CS9137. O formato é o mesmo tanto se o projeto consumidor usa Microsoft.NET.Sdk quanto Microsoft.NET.Sdk.Web: reproduzi com uma API criada por dotnet new web cujo único caminho até o pacote era um ProjectReference para uma biblioteca de configurações compartilhadas. Ser um projeto web não ajuda em nada aqui.
Bases de código reais caem nisso de três formas reconhecíveis: uma biblioteca estilo ServiceDefaults do Aspire que centraliza o AddOpenApi, um monólito modular em que cada módulo registra o próprio documento, e um host de plugins ou CMS (módulos do Umbraco e do OrchardCore aparecem nos relatos de problemas) em que o pacote fica em um pacote base um nível acima.
A correção, em ordem de preferência
1. Adicione a propriedade ao projeto que falha
Copie o namespace da mensagem de erro e cole a propriedade no .csproj que o erro cita:
<!-- .NET 10 / .NET 11, Microsoft.AspNetCore.OpenApi 10.0.x -->
<PropertyGroup>
<InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.AspNetCore.OpenApi.Generated</InterceptorsNamespaces>
</PropertyGroup>
Mantenha o $(InterceptorsNamespaces); no início. Outros geradores acrescentam valores à mesma propriedade, e uma atribuição seca joga fora as entradas deles. Assim o gerador continua rodando, então os comentários XML continuam chegando ao documento.
Se vários projetos da solução registram documentos, coloque isso uma vez só no Directory.Build.props em vez de repetir. Os targets do pacote são importados depois do corpo do projeto e acrescentam ao que encontrarem, então os dois nunca brigam.
2. Dê ao projeto o próprio PackageReference
Se o projeto realmente chama AddOpenApi, ele tem direito legítimo ao pacote:
dotnet add Modules package Microsoft.AspNetCore.OpenApi
Isso traz o build/Microsoft.AspNetCore.OpenApi.targets, que define a propriedade para você. Verifiquei que isso elimina o erro sem nenhuma outra mudança. É mais honesto que o arranjo transitivo e sobrevive a alguém reorganizar as referências de projeto depois.
3. Desligue o gerador naquele projeto
Se o projeto não tem interesse em comentários XML, remova o analisador em vez de autorizar a saída dele. A documentação oficial mostra isso com a propriedade de caminho do pacote; a forma baseada em itens é menos frágil:
<!-- .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>
O build fica verde, e o custo é que o texto de <summary> e <param> deixa de aparecer na saída OpenAPI daquele projeto. O mesmo efeito, aplicado pela outra ponta, vem de PrivateAssets="analyzers" no PackageReference de cima, que impede o gerador de alcançar qualquer consumidor daquela biblioteca:
<!-- Defaults.csproj -- .NET 10, keeps the generator out of downstream projects -->
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.10" PrivateAssets="analyzers" />
As duas são correções verificadas. Recorra a elas quando um servidor de build está vermelho e você precisa do pipeline de volta antes da documentação.
Detalhes que mantêm o build vermelho
InterceptorsPreviewNamespaces ainda funciona, e não é a grafia moderna. A propriedade antiga é respeitada pelo compilador de C# 14 no SDK 10.0.201, sem avisos, e o próprio SDK continua usando ela para os seus três namespaces. Use InterceptorsNamespaces em código novo, mas não “conserte” um build herdado renomeando uma propriedade que já funciona.
Desligar a documentação XML não desliga o gerador. Definir <GenerateDocumentationFile>false</GenerateDocumentationFile> parece que deveria contornar um gerador de comentários XML. Não contorna. O gerador continua interceptando AddOpenApi, e o mesmo CS9137 volta na linha 597 em vez da 598. Se você quer se livrar dele, remova o analisador.
A interceptação é por ponto de chamada e por compilação. Essa custa horas às pessoas depois que o build já está verde. Os transformadores ficam embutidos na compilação onde a chamada AddOpenApi() aparece fisicamente, e carregam apenas os comentários XML daquela compilação. Mova a chamada para uma biblioteca de configurações compartilhadas e os resumos do seu projeto de API somem do documento em silêncio. Medido sobre a reprodução acima, com AddOpenApi() embutido no projeto de API:
{
"summary": "Gets a single widget by id.",
"parameters": [
{ "name": "id", "description": "The widget identifier." }
]
}
Com o mesmo endpoint documentado da mesma forma, mas com AddOpenApi() chamado a partir da biblioteca referenciada, tanto o summary quanto a description do parâmetro somem. Mantenha a chamada de AddOpenApi() no projeto cujos comentários você quer, ou alimente os arquivos XML dos outros assemblies via AdditionalFiles.
Um nome de documento que não seja literal não é interceptado. AddOpenApi(documentName) onde documentName é uma variável não produz interceptador nenhum, então você não recebe erro nem comentários XML. Só strings literais são reconhecidas.
EmitCompilerGeneratedFiles pode criar um segundo erro, pior. Inspecionar o arquivo gerado é o instinto certo, mas se você também apontar CompilerGeneratedFilesOutputPath para uma pasta dentro do diretório do projeto, o arquivo emitido vira uma entrada real da compilação no build seguinte:
Generated\...\OpenApiXmlCommentSupport.generated.cs(67,42):
error CS0433: The type 'XmlComment' exists in both 'Api' and 'Api'
Deixe o caminho de saída dentro de obj, ou adicione um <Compile Remove> correspondente.
Interceptadores não são o problema de LangVersion que parecem ser. Eles são legais desde o C# 12, então um <LangVersion>12.0</LangVersion> explícito compila o arquivo gerado sem problema assim que o namespace está autorizado. Não saia caçando versões de linguagem.
Confira o grafo inteiro, não um projeto só. Depois de corrigir o projeto citado no erro, o próximo projeto acima na cadeia costuma falhar do mesmo jeito no build seguinte. dotnet msbuild <project> -getProperty:InterceptorsNamespaces em toda a solução encontra todos de uma vez.
Relacionados
O gerador por trás deste erro é a mesma maquinaria descrita em o que é um gerador de código-fonte e quando você precisa de um, e o mecanismo de interceptadores em si está coberto em interceptadores do C# 12. Se você chegou aqui no meio de uma atualização, o outro erro de build desta família de pacotes é o tipo OpenApiReference que sumiu, e o movimento mais amplo está em migrar do Swashbuckle para o gerador de OpenAPI embutido. Quando o documento voltar a compilar, personalizá-lo com transformadores de operação e de schema é o próximo passo, e servi-lo com o Scalar coloca uma interface na frente dele.
Fontes
- Suporte a comentários de documentação XML no OpenAPI do ASP.NET Core, que documenta as sobrecargas interceptadas de
AddOpenApi, a restrição de strings literais e a receita para remover o analisador. - Issue 61177 do dotnet/aspnetcore, a issue de acompanhamento para projetos que precisam adicionar
InterceptorsNamespacesna mão. - Issue 77877 do dotnet/roslyn, o relato de CS9137 com o SDK da versão prévia 3 do .NET 10, fechado como duplicado da issue do ASP.NET Core.
- Issue 63623 do dotnet/aspnetcore, um relato do erro persistindo depois de adicionar a propriedade.
- Microsoft.AspNetCore.OpenApi.csproj, onde o arquivo de targets é empacotado em
builde não embuildTransitive.
Comments
Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.