Updated October 2026 for .NET 10 (LTS) and Swashbuckle.AspNetCore 10.x.
Swagger UI opens but shows “Failed to load API definition” instead of your endpoints. The UI itself is fine. It could not load or read the swagger.json document behind it. The fastest way to the fix is to open that JSON URL directly and read the real error, then match it to one of the causes below.
The error
Failed to load API definition. Fetch error undefined /swagger/v1/swagger.json
You may also see Fetch error: Internal Server Error /swagger/v1/swagger.json or Not Found.
Step 1: Open swagger.json directly
Browse to https://localhost:5001/swagger/v1/swagger.json (use your own port). What you see tells you where to look:
- 500 with an exception message → a problem in your controllers or models. See causes 1 to 3.
- 404 Not Found → Swagger is not enabled for this environment, or the path is different. See causes 4 and 5.
- The JSON loads fine → the UI is pointing at the wrong URL or is blocked by the browser. See causes 5 and 6.
The full exception is also written to your app’s console and logs.
Cause 1: Two actions share the same route and HTTP method
Conflicting method/path combination "GET api/Orders" for actions ... Actions require a unique method/path combination for Swagger/OpenAPI 2.0 and 3.0.
Give each action a unique route:
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
[HttpGet] // GET api/orders
public IActionResult GetAll() => Ok();
[HttpGet("{id:int}")] // GET api/orders/5
public IActionResult GetById(int id) => Ok();
}
As a temporary workaround only, you can tell Swashbuckle to keep the first match. The other action will be missing from the docs:
builder.Services.AddSwaggerGen(c =>
c.ResolveConflictingActions(descriptions => descriptions.First()));
Cause 2: A public controller method has no HTTP attribute
Ambiguous HTTP method for action - ... Actions require an explicit HttpMethod binding for Swagger/OpenAPI 3.0
Every public method in a controller is treated as an action. Add [HttpGet], [HttpPost] and so on, or hide helper methods:
[NonAction]
public decimal CalculateTax(decimal amount) => amount * 0.13m;
Better still, make helpers private or move them into a service.
Cause 3: Two models have the same class name
Can't use schemaId "$Customer" for type "$Sales.Customer". The same schemaId is already used for type "$Billing.Customer"
Classes with the same name in different namespaces clash. Use the full name as the schema id:
builder.Services.AddSwaggerGen(c =>
c.CustomSchemaIds(type => type.FullName));
Cause 4: Swagger only runs in Development
The default template enables Swagger only when app.Environment.IsDevelopment() is true. On IIS, Azure or another server the environment is usually Production, so swagger.json returns 404. If you really want Swagger on that server, enable it for the environments you choose:
if (app.Environment.IsDevelopment() || app.Environment.IsStaging())
{
app.UseSwagger();
app.UseSwaggerUI();
}
Think twice before exposing API docs publicly in production. See Enable Swagger per environment.
Cause 5: The UI points to the wrong URL
This is common when the app runs under a sub-path, for example an IIS virtual directory (https://server/MyService/) or behind a reverse proxy. An absolute path such as /swagger/v1/swagger.json then points to the wrong place. Use a relative path, which works in both cases:
app.UseSwagger();
app.UseSwaggerUI(c =>
c.SwaggerEndpoint("v1/swagger.json", "My API v1")); // relative to /swagger
If you change the JSON route, it must include {documentName}, and the UI must use the same path:
app.UseSwagger(c =>
c.RouteTemplate = "docs/{documentName}/swagger.json");
app.UseSwaggerUI(c =>
{
c.RoutePrefix = "docs";
c.SwaggerEndpoint("v1/swagger.json", "My API v1");
});
The document name is case-sensitive: v1 in SwaggerDoc("v1", ...) must match v1 in the URL, not V1.
Using built-in OpenAPI? With AddOpenApi() and MapOpenApi(), the document is at /openapi/v1.json, not /swagger/v1/swagger.json. Point the UI there: c.SwaggerEndpoint("/openapi/v1.json", "My API v1"). See AddSwaggerGen vs AddOpenApi in .NET 10.
Cause 6: CORS or Content Security Policy blocks the request
If swagger.json opens directly but the UI still fails, press F12 and check the browser Console and Network tabs. A CORS or CSP error means the server’s security headers block the UI from loading the document or its own scripts. See Content Security Policy for Swagger UI.
FAQ
It works locally but not after deployment. Why?
Almost always cause 4 (Swagger enabled only in Development) or cause 5 (the app runs under a sub-path on the server). Open the JSON URL on the server to confirm.
Do I need both a title and version in SwaggerDoc?
Yes, when you call SwaggerDoc yourself: c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }). With Swashbuckle 10, keep using Microsoft.OpenApi.Models; for OpenApiInfo and add using Microsoft.OpenApi; if you also write custom filters.
Related
- Fix: IServiceCollection does not contain a definition for AddSwaggerGen
- Show or hide API actions in Swagger
- Export Swagger JSON or YAML
- Free tool: generate C# request/response classes from JSON
Sources: Swashbuckle.AspNetCore on GitHub · Microsoft Learn: OpenAPI support in ASP.NET Core

You did a good job explaining how to solve this common problem. Thanks for the information!