RicoSuter/NSwag · error · InvalidOperationException

The template directory

Error message

The template directory {CodeGenerators.OpenApiToCSharpControllerCommand.TemplateDirectory}\" does not exist

What it means

Same validation for OpenApiToCSharpControllerCommand: a non-null TemplateDirectory that does not exist after absolute-path conversion throws this InvalidOperationException (note the malformed message string with a stray quote — a cosmetic bug, but the condition is identical).

Solutions

  1. Correct templateDirectory so it points to an existing directory.
  2. Use an absolute path in the document, or run from the directory the relative path assumes.
  3. Remove the templateDirectory entry to fall back to built-in templates.

Example fix

// before
"templateDirectory": "templates/controller"
// after
"templateDirectory": "D:/src/templates/controller"
Defensive patterns

Strategy: validation

Validate before calling

var td = doc.CodeGenerators?.OpenApiToCSharpControllerCommand?.TemplateDirectory;
if (!string.IsNullOrEmpty(td) && !Directory.Exists(Path.GetFullPath(td, basePath)))
    throw new DirectoryNotFoundException($"Template directory not found: {td}");

Try / catch

try { var json = document.ToJsonWithRelativePaths(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("does not exist") && ex.Message.Contains("template directory"))
{ Console.Error.WriteLine($"Fix csharpController templateDirectory: {ex.Message}"); throw; }

Prevention

When it happens

Trigger: CodeGenerators.OpenApiToCSharpControllerCommand.TemplateDirectory is set but Directory.Exists returns false after ConvertToAbsolutePath — path typo, missing directory, or wrong working directory for a relative path.

Common situations: C# controller (ASP.NET Core web API) generation documents with custom templates referenced relatively; running from another directory or machine where the templates folder is absent.

Related errors


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

Appendix: source

Thrown at src/NSwag.Commands/NSwagDocumentBase.cs:357

                CodeGenerators.OpenApiToCSharpClientCommand.ContractsOutputFilePath = ConvertToAbsolutePath(
                    CodeGenerators.OpenApiToCSharpClientCommand.ContractsOutputFilePath);
                CodeGenerators.OpenApiToCSharpClientCommand.TemplateDirectory = ConvertToAbsolutePath(
                    CodeGenerators.OpenApiToCSharpClientCommand.TemplateDirectory);

                if (CodeGenerators.OpenApiToCSharpClientCommand.TemplateDirectory != null && !Directory.Exists(CodeGenerators.OpenApiToCSharpClientCommand.TemplateDirectory))
                {
                    throw new InvalidOperationException($"The template directory \"{CodeGenerators.OpenApiToCSharpClientCommand.TemplateDirectory}\" does not exist");
                }
            }

            if (CodeGenerators.OpenApiToCSharpControllerCommand != null)
            {
                CodeGenerators.OpenApiToCSharpControllerCommand.TemplateDirectory = ConvertToAbsolutePath(
                    CodeGenerators.OpenApiToCSharpControllerCommand.TemplateDirectory);

                if (CodeGenerators.OpenApiToCSharpControllerCommand.TemplateDirectory != null && !Directory.Exists(CodeGenerators.OpenApiToCSharpControllerCommand.TemplateDirectory))
                {
                    throw new InvalidOperationException($"The template directory {CodeGenerators.OpenApiToCSharpControllerCommand.TemplateDirectory}\" does not exist");
                }
            }

            foreach (var generator in CodeGenerators.Items.Concat(SwaggerGenerators.Items))
            {
                generator.OutputFilePath = ConvertToAbsolutePath(generator.OutputFilePath);
            }
        }

        private void ConvertToRelativePaths()
        {
            if (SwaggerGenerators.FromDocumentCommand != null)
            {
                if (!SwaggerGenerators.FromDocumentCommand.Url.StartsWith("http://", StringComparison.OrdinalIgnoreCase)
                    && !SwaggerGenerators.FromDocumentCommand.Url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
                {
                    SwaggerGenerators.FromDocumentCommand.Url = ConvertToRelativePath(SwaggerGenerators.FromDocumentCommand.Url);
                }

View on GitHub (pinned to 63daf8fcc3)