RicoSuter/NSwag · error · InvalidOperationException

The method ' ' on path ' ' is registered multiple times for…

Error message

The method '{operation.Method}' on path '{path}' is registered multiple times for action {string.Join(", ", conflictingOperationDisplayNames)} (check the DefaultUrlTemplate setting [default for Web API: 'api/{controller}/{id}'; for MVC projects: '{controller}/{action}/{id?}']).

What it means

The WebApi generator's AddOperationDescriptionsToDocument (called from GenerateForController) throws InvalidOperationException when two operations on a controller resolve to the same path and HTTP method under the configured DefaultUrlTemplate, since an OpenAPI path item allows one operation per method. The message also hints that the DefaultUrlTemplate setting (default 'api/{controller}/{id}' for Web API, '{controller}/{action}/{id?}' for MVC) may be causing the collision.

Solutions

  1. Check/fix the DefaultUrlTemplate setting so paths differ per action (e.g. use '{controller}/{action}/{id?}' for MVC-style controllers).
  2. Give each colliding action a distinct route template ([Route] / [HttpPost("...")]) or HTTP method.
  3. Remove or merge the duplicate action, or hide it from the document.
  4. Use the action names listed in the message (GetDisplayName output) to locate the exact conflicting methods.

Example fix

// before (config)
settings.DefaultUrlTemplate = "api/{controller}/{id}"; // all POST actions collide
// after (config)
settings.DefaultUrlTemplate = "api/{controller}/{action}/{id?}";
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the URL template distinguishes actions before generating
var template = settings.DefaultUrlTemplate;
bool distinguishesActions = template.Contains("{action}") ||
    controllerActions.GroupBy(a => ResolvePath(template, a)).All(g => g.Count() == 1);

Try / catch

try { document = generator.GenerateForControllers(controllerTypes); }
catch (InvalidOperationException ex) when (ex.Message.Contains("is registered multiple times"))
{
    logger.LogError(ex, "Duplicate path/method under DefaultUrlTemplate {Template}", settings.DefaultUrlTemplate);
}

Prevention

When it happens

Trigger: Running GenerateForControllers/WebApiOpenApiDocumentGenerator when two actions on a controller produce identical (path, method) tuples — e.g. two POST actions with no route template, or a custom DefaultUrlTemplate that drops the {action} segment so all actions share one path.

Common situations: Setting DefaultUrlTemplate to 'api/{controller}/{id}' while the controller has multiple actions of the same HTTP method; overloading actions without route attributes; copy-pasted actions; switching between Web API and MVC templates without adjusting route templates.

Related errors


AI-assisted analysis of RicoSuter/NSwag@63daf8fcc3 (2026-09-14). Data as JSON: /api/errors/eac7297e72098a0d. Report an issue: GitHub.

Appendix: source

Thrown at src/NSwag.Generation.WebApi/WebApiOpenApiDocumentGenerator.cs:230

                var addOperation = RunOperationProcessors(document, controllerType, method, operation, allOperation, swaggerGenerator, schemaResolver);
                if (addOperation)
                {
                    var path = operation.Path.Replace("//", "/");

                    if (!document.Paths.TryGetValue(path, out var pathItem))
                    {
                        pathItem = [];
                        document.Paths[path] = pathItem;
                    }

                    if (pathItem.ContainsKey(operation.Method))
                    {
                        var conflictingOperationDisplayNames = operations
                            .Where(t => t.Item1.Path == operation.Path && t.Item1.Method == operation.Method)
                            .Select(t => GetDisplayName(controllerType, t.Item2))
                            .ToList();

                        throw new InvalidOperationException($"The method '{operation.Method}' on path '{path}' is registered multiple times for action {string.Join(", ", conflictingOperationDisplayNames)} " +
                            "(check the DefaultUrlTemplate setting [default for Web API: 'api/{controller}/{id}'; for MVC projects: '{controller}/{action}/{id?}']).");
                    }

                    pathItem[operation.Method] = operation.Operation;
                    addedOperations++;
                }
            }

            return addedOperations > 0;
        }

        private static string GetDisplayName(Type controllerType, MethodInfo method)
        {
            return $"{controllerType.FullName}.{method.Name} ({controllerType.Assembly.GetName().Name})";
        }

        private bool RunOperationProcessors(OpenApiDocument document, Type controllerType, MethodInfo methodInfo, OpenApiOperationDescription operationDescription,
            List<OpenApiOperationDescription> allOperations, OpenApiDocumentGenerator generator, OpenApiSchemaResolver schemaResolver)

View on GitHub (pinned to 63daf8fcc3)