Troubleshooting & FAQ
Common Issues
AddDefaultsDocumentTransformer throws ArgumentNullException
Cause: OpenApiOptions is null when calling the extension method.
Fix: Ensure AddOpenApi() is called before chaining:
// ❌
OpenApiOptions? opts = null;
opts.AddDefaultsDocumentTransformer(); // throws
// ✅
builder.Services.AddOpenApi(options =>
{
options.AddDefaultsDocumentTransformer();
});
DependencyInjectionExtensions not found after upgrading to v10.1.1
Cause: In v10.1.1 the class was renamed from DependencyInjectionExtensions to OpenApiOptionsExtensions (and its methods are now C# 14 extension members).
Fix: Replace class-name references — typeof(DependencyInjectionExtensions), static calls, reflection strings — with OpenApiOptionsExtensions. Regular extension-method call sites like options.AddDefaultsDocumentTransformer() are unaffected.
RA.Utilities.Api.Results no longer compiles in my custom transformer
Cause: This package now references RA.Utilities.Api.Response 10.1.0, which moved its models from the RA.Utilities.Api.Results namespace to RA.Utilities.Api.Response.
Fix: Update the using directive in your custom transformers or examples:
// Before
using RA.Utilities.Api.Results;
// After
using RA.Utilities.Api.Response;
OpenApiOperationUtilities.AddGeneralErrorResponse and the DefaultResponsesOperationTransformer schema also use ErrorResponse from this package; the OpenApi public API itself is unchanged.
AddHealthChecksDocumentTransformer(tags) doesn't add the health check endpoints
Cause: Known bug in v10.1.0 through v10.3.0 — the method registers HeadersParameterTransformer instead of HealthChecksDocumentTransformer, and ignores tags.
Fix: Register the default pipeline instead:
builder.Services.AddOpenApi(options =>
{
options.AddDefaultsDocumentTransformer();
});
AddDefaultsDocumentTransformer() registers HealthChecksDocumentTransformer after the Bearer security transformer, so /health and /alive stay anonymous.
Group summary or description doesn't appear on the tag
Cause: One of the following:
GroupTagsDocumentTransformerisn't registered.AddDefaultsDocumentTransformer()registers it automatically; if you register transformers individually, calloptions.AddGroupTagsDocumentTransformer(...).- The route group and its endpoints carry no tags. Group text is written only to the tags returned by
WithTags(...). - The tag already has a non-empty description. Group text only fills empty descriptions — an explicit
AddTagOperationTransformer()description always wins.
Fix: Register the transformer and tag the group:
builder.Services.AddOpenApi(options =>
{
options.AddDefaultsDocumentTransformer(); // includes GroupTagsDocumentTransformer
});
var orders = app.MapGroup("/orders")
.WithTags("Orders")
.WithGroupSummary("Order management")
.WithGroupDescription("Create, update, and track customer orders.");
AddResponseExamples ignores my MediaType
Cause: AddResponseExamples forwards each item to AddResponseExample without the per-item MediaType, so batched response examples always use application/json.
Fix: Add the examples individually when you need another media type:
OpenApiOperationUtilities.AddResponseExample(
operation,
StatusCodes.Status400BadRequest,
"ValidationError",
example,
mediaType: "application/problem+json");
Swagger UI doesn't show the Authorize button
Cause: BearerSecurityDocumentTransformer wasn't registered, or JWT Bearer authentication isn't configured.
Fix: Register the transformer and ensure authentication is set up:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(/* ... */);
builder.Services.AddOpenApi(options =>
options.AddBearerSecurityDocumentTransformer());
The transformer checks for registered authentication schemes named "Bearer" or "BearerToken".
Header parameters aren't appearing in the OpenAPI doc
Cause: HeadersParameterSettings aren't bound from configuration, or HeadersParameterTransformer isn't registered.
Fix: Bind the settings and register the transformer:
builder.Services.Configure<HeadersParameterSettings>(
builder.Configuration.GetSection(HeadersParameterSettings.AppSettingsKey));
builder.Services.AddOpenApi(options =>
options.AddHeadersParameterTransformer());
FluentValidation rules aren't reflected in the schema
Cause: The validators aren't registered in DI, or AddFluentValidationRules() wasn't called.
Fix: Register validators and the transformer:
// Register validators
builder.Services.AddValidatorsFromAssembly(typeof(Program).Assembly);
// Register schema transformer
builder.Services.AddOpenApi(options =>
options.AddFluentValidationRules());
The transformer resolves IValidator<T> from DI for each schema type. If the validator isn't registered, the schema is left unchanged.
Value objects have no type, pattern, or length in the schema
Cause: ValueObjectSchemaTransformer isn't registered. The OpenAPI generator cannot see the validation performed by the value object constructors, so it emits Email, Currency, SSN, and IBAN as property-less objects.
Fix: Register the default pipeline or the transformer explicitly:
builder.Services.AddOpenApi(options =>
options.AddValueObjectSchemaTransformer());
AddDefaultsDocumentTransformer() already registers it. Once registered, Email, Currency, SSN, and IBAN become string schemas with format, pattern, minLength, and maxLength, and Money gets a description and example. The transformer also covers route, query, and header parameters.
Enum descriptions aren't appearing
Cause: Either the XML documentation file path is wrong, or the file doesn't exist, or the enum members don't have XML comments.
Fix: Verify the XML file is generated and the path is correct:
var xmlPath = Path.Combine(AppContext.BaseDirectory, "MyApi.xml");
if (!File.Exists(xmlPath))
{
throw new FileNotFoundException($"XML doc file not found: {xmlPath}");
}
builder.Services.AddOpenApi(options =>
options.AddEnumXmlDescriptionTransformer(xmlPath));
Also ensure your enum members have <summary> XML comments.
Polymorphism discriminator isn't working
Cause: The base schema name doesn't match the type passed to AddPolymorphismDocumentTransformer<T>().
Fix: Pass the correct base type as the generic parameter:
// ✅ The base type T must match the schema you want to transform
options.AddPolymorphismDocumentTransformer<Animal>(new Dictionary<string, Type>
{
{ "Cat", typeof(Cat) },
{ "Dog", typeof(Dog) },
});
FAQ
What's the difference between a Document Transformer and an Operation Transformer?
| Document Transformer | Operation Transformer | |
|---|---|---|
| Interface | IOpenApiDocumentTransformer | IOpenApiOperationTransformer |
| Scope | Entire OpenAPI document | Individual API operation |
| Use for | Info, security schemes, global headers | Per-operation responses, parameters |
Do I need AddOpenApi() before using these transformers?
Yes — the extension methods extend OpenApiOptions, so they must be called from the AddOpenApi(Action<OpenApiOptions>) overload:
builder.Services.AddOpenApi(options =>
{
options.AddDefaultsDocumentTransformer();
options.AddFluentValidationRules();
});
Note that AddOpenApi() itself returns IServiceCollection, so AddOpenApi().AddDefaultsDocumentTransformer() does not compile.
Can I use multiple schema transformers together?
Yes. Register them all:
builder.Services.AddOpenApi(options =>
{
options.AddFluentValidationRules();
options.AddEnumXmlDescriptionTransformer(xmlPath);
});
Why are the transformers internal?
Transformers are internal sealed to enforce registration through the provided extension methods. This ensures consistent configuration, proper dependency injection, and the ability to change internal implementations without breaking consumers.
Does AddDefaultsDocumentTransformer() include everything?
No. It registers five document transformers — DocumentInfoTransformer, BearerSecurityDocumentTransformer, HeadersParameterTransformer, HealthChecksDocumentTransformer, and GroupTagsDocumentTransformer — plus the ValueObjectSchemaTransformer. The operation transformer (DefaultResponsesOperationTransformer) and the remaining schema transformers must be registered separately.
How do I exclude specific endpoints from a transformer?
Document transformers apply globally. To exclude specific endpoints, use a custom operation transformer that checks the operation's metadata, or write a custom document transformer that filters document.Paths before delegating. Configuration settings such as HeadersParameterSettings are global; they do not support per-endpoint overrides.
Known Limitations
AddHealthChecksDocumentTransformer(tags)is broken in v10.1.0 through v10.3.0: it registersHeadersParameterTransformerand ignorestags. UseAddDefaultsDocumentTransformer().AddGroupTagsDocumentTransformer(tags)ignorestags: the argument is required by the current signature but unused; group text comes fromWithGroupSummary()/WithGroupDescription(). UseAddDefaultsDocumentTransformer(), which registers the transformer automatically.- Group documentation requires tags:
WithGroupSummary()/WithGroupDescription()write to the tags the group's endpoints carry; without.WithTags(...)there is no tag to describe. Existing tag descriptions are never overwritten. AddResponseExamplesignores per-itemMediaType: batched response examples always useapplication/json; useAddResponseExamplefor custom media types.- No endpoint exclusion: Document transformers apply to all operations. Use custom transformers for per-endpoint behavior.
- Single XML file:
EnumXmlSchemaTransformercurrently supports only one XML documentation file. - FluentValidation scope: Only validators registered in the DI container are discovered. Attributes-based validation (DataAnnotations) is not supported.
- Numeric
responseTypein default examples:DefaultResponsesOperationTransformerserializesnew ErrorResponse()with defaultSystem.Text.Jsonoptions, so the example'sresponseTypeis numeric. RegisterJsonStringEnumConverterfor string values.