RicoSuter/NSwag · error · ArgumentException

does not implement property 'Template

Error message

{type.FullName}  does not implement property 'Template'

What it means

RouteAttributeFacade wraps a route-like attribute and caches its 'Template' property via reflection (type.GetRuntimeProperty("Template")). If the attribute's runtime type does not expose a public 'Template' property, the facade constructor throws ArgumentException with the full type name. It is thrown when NSwag's WebApi generator encounters an attribute it treats as a route attribute but which lacks the expected surface.

Solutions

  1. Ensure the attribute class declares a public string property named exactly 'Template' (with getter).
  2. Replace the custom attribute with the standard Microsoft.AspNetCore.Mvc.RouteAttribute.
  3. If you must use a custom attribute, derive from RouteAttribute so Template is inherited.
  4. Verify with reflection that GetRuntimeProperty("Template") returns non-null for the attribute type in the failing assembly.

Example fix

// before
public class MyRouteAttribute : Attribute { public string Path { get; set; } }

// after
public class MyRouteAttribute : Attribute { public string Template { get; set; } }
Defensive patterns

Strategy: validation

Validate before calling

// Verify custom route attributes expose 'Template'
var ok = typeof(MyRouteAttribute).GetRuntimeProperty("Template") != null;
if (!ok) throw new InvalidOperationException("Custom route attribute must expose public 'Template' property");

Type guard

function hasTemplateProperty(attr) {
  return attr != null && typeof attr.Template === "string"; // C#: attr.GetType().GetRuntimeProperty("Template") != null
}

Try / catch

try { document = generator.Generate(settings); }
catch (ArgumentException ex) when (ex.Message.Contains("does not implement property 'Template'"))
{
    logger.LogError(ex, "Custom route attribute lacks 'Template' property");
}

Prevention

When it happens

Trigger: Passing a custom or third-party route attribute (via UseRouteTemplate/replacement attributes or a custom controller attribute scan) whose class does not declare a public property named exactly 'Template'; inheriting from RouteAttribute in an assembly compiled against a different Microsoft.AspNetCore routing package where the property is virtual/renamed/non-public.

Common situations: Custom attribute named/behaving like a route attribute but exposing 'Name'/'Path' instead of 'Template'; package version changes making the property non-public; using an HttpMethodAttribute-derived attribute without a Template property.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at src/NSwag.Generation.WebApi/Infrastructure/RouteAttributeFacade.cs:36

    /// </summary>
    internal sealed class RouteAttributeFacade
    {
        private readonly PropertyInfo _template;

        private RouteAttributeFacade(Attribute attr, PropertyInfo template)
        {
            Attribute = attr;
            _template = template;
        }

        public RouteAttributeFacade(Attribute attr)
        {
            var type = attr.GetType();

            _template = type.GetRuntimeProperty("Template");
            if (_template == null)
            {
                throw new ArgumentException($"{type.FullName}  does not implement property 'Template'");
            }

            Attribute = attr;
        }

        public Attribute Attribute { get; }

        public string Template => (string)_template.GetValue(Attribute);

        public static RouteAttributeFacade TryMake(Attribute a)
        {
            var type = a.GetType();
            var typeInfo = type.GetTypeInfo();

            if (type.Name == "RouteAttribute" ||
                typeInfo.ImplementedInterfaces.Any(i => i.Name == "IHttpRouteInfoProvider") ||
                typeInfo.ImplementedInterfaces.Any(i => i.Name == "IRouteTemplateProvider")) // .NET Core
            {

View on GitHub (pinned to 63daf8fcc3)