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

Sources: Swashbuckle.AspNetCore on GitHub · Microsoft Learn: OpenAPI support in ASP.NET Core

31 thoughts on “Fix: Swagger “Failed to load API definition” (swagger.json fetch error) in .NET 10”

Leave a Reply

Your email address will not be published. Required fields are marked *