#5336·NSwag

NSwag + NJsonSchema fails to process Azure's openapi.json "...because no document path is available." (with patch)

Author: daiplusplusCreated Feb 4, 2026Updated Jul 14, 2026
Labelstype: bug

Describe the bug

Azure's openapi.json (permalink, and attached): - causes NSwagStudio to crash, and NJsonSchema to complain; in-part, due to external references.

  1. Get the current NSwag master branch HEAD (2a5ca6e199035833984aa270f059a93e3f513bfe) and build it locally (using build.bat works for me).

  2. Get the current NJsonSchema master branch HEAD (6d3580c03079107bacf8869e5e64df7feb138cd9) and build it locally (using build.bat works for me).

  3. Clone the azure-rest-api-specs repo locally and checkout commit 09fee50b88b6951671d9b82597759cd3f4b3776b - then locate $\specification\web\resource-manager\Microsoft.Web\AppService\stable\2025-05-01\openapi.json and load that into NSwagStudio and click the Generate button.

    • Ensure that you also have "$\specification\common-types\resource-management\v5\types.json at that exact location too.
  4. You'll get this error message popup:

    System.NotSupportedException: Could not resolve the JSON path '../../../../../../common-types/resource-management/v5/types.json#/parameters/ApiVersionParameter' because no document path is available.
    
    Runtime: Net80
       at NJsonSchema.JsonReferenceResolver.ResolveReferenceAsync(Object rootObject, String jsonPath, Type targetType, IContractResolver contractResolver, Boolean append, CancellationToken cancellationToken)
       at NJsonSchema.JsonReferenceResolver.ResolveReferenceAsync(Object rootObject, String jsonPath, Type targetType, IContractResolver contractResolver, CancellationToken cancellationToken)
       at NJsonSchema.JsonSchemaReferenceUtilities.JsonReferenceUpdater.VisitJsonReferenceAsync(IJsonReference reference, String path, String typeNameHint, CancellationToken cancellationToken)
       at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, String path, String typeNameHint, ISet`1 checkedObjects, Action`1 replacer, CancellationToken cancellationToken)
       at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, String path, String typeNameHint, ISet`1 checkedObjects, Action`1 replacer, CancellationToken cancellationToken)
       at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, String path, String typeNameHint, ISet`1 checkedObjects, Action`1 replacer, CancellationToken cancellationToken)
       at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, String path, String typeNameHint, ISet`1 checkedObjects, Action`1 replacer, CancellationToken cancellationToken)
       at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, String path, String typeNameHint, ISet`1 checkedObjects, Action`1 replacer, CancellationToken cancellationToken)
       at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, String path, String typeNameHint, ISet`1 checkedObjects, Action`1 replacer, CancellationToken cancellationToken)
       at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, CancellationToken cancellationToken)
       at NJsonSchema.JsonSchemaReferenceUtilities.JsonReferenceUpdater.VisitAsync(Object obj, CancellationToken cancellationToken)
       at NJsonSchema.JsonSchemaReferenceUtilities.UpdateSchemaReferencesAsync(Object rootObject, JsonReferenceResolver referenceResolver, IContractResolver contractResolver, CancellationToken cancellationToken)
       at NJsonSchema.Infrastructure.JsonSchemaSerialization.FromJsonWithLoaderAsync[T](Func`1 loader, SchemaType schemaType, String documentPath, Func`2 referenceResolverFactory, IContractResolver contractResolver, CancellationToken cancellationToken)
       at NSwag.OpenApiDocument.FromJsonAsync(String data, String documentPath, SchemaType expectedSchemaType, Func`2 referenceResolverFactory, CancellationToken cancellationToken) in /_/src/NSwag.Core/OpenApiDocument.cs:line 204
       at NSwag.Commands.Generation.FromDocumentCommand.RunAsync() in /_/src/NSwag.Commands/Commands/Generation/FromDocumentCommand.cs:line 61
       at NSwag.Commands.Generation.FromDocumentCommand.RunAsync(CommandLineProcessor processor, IConsoleHost host) in /_/src/NSwag.Commands/Commands/Generation/FromDocumentCommand.cs:line 52
       at NSwag.Commands.NSwagDocumentBase.GenerateSwaggerDocumentAsync() in /_/src/NSwag.Commands/NSwagDocumentBase.cs:line 266
       at NSwag.Commands.NSwagDocument.ExecuteAsync() in /_/src/NSwag.Commands/NSwagDocument.cs:line 63
       at NSwag.Commands.Document.ExecuteDocumentCommand.ExecuteDocumentAsync(IConsoleHost host, String filePath) in /_/src/NSwag.Commands/Commands/Document/ExecuteDocumentCommand.cs:line 72
       at NSwag.Commands.Document.ExecuteDocumentCommand.RunAsync(CommandLineProcessor processor, IConsoleHost host) in /_/src/NSwag.Commands/Commands/Document/ExecuteDocumentCommand.cs:line 29
       at NConsole.CommandLineProcessor.ProcessSingleAsync(String[] args, Object input) in /_/src/NSwag.Commands/NConsole/CommandLineProcessor.cs:line 184
       at NConsole.CommandLineProcessor.ProcessAsync(String[] args, Object input) in /_/src/NSwag.Commands/NConsole/CommandLineProcessor.cs:line 120
       at NSwag.Commands.NSwagCommandProcessor.ProcessAsync(String[] args) in /_/src/NSwag.Commands/NSwagCommandProcessor.cs:line 61
  5. I was able to fix this by adding documentPath (as either a new JSON property or as method parameter) to the following types/members, as they pass values from NSwagStudio, to the temp files on-disk, and into NJsonSchema:

    • NSwagDocument
    • InputOutputCommandBase.GetInputSwaggerDocument
    • OutputCommandBase.ReadSwaggerDocumentAsync
    • FromDocumentCommand.DocumentPath,
    • ReadSwaggerDocumentAsync
    • OpenApiDocumentGeneratorSettings
    • OpenApiDocument.FromJsonAsync
    • OpenApiYamlDocument.FromYamlAsync (for consistency's sake)
    • WebApiOpenApiDocumentGenerator.CreateDocumentAsync
    • AspNetCoreOpenApiDocumentGenerator.CreateDocumentAsync (for consistency's sake)
  6. BTW, I noticed that NSwag/NJsonSchema is (incorrectly?) sensitive to whether or not the documentPath ends with a slash;

    • i.e.: it works when the path is C:\git\clones\azure-rest-api-specs\specification\web\resource-manager\Microsoft.Web\AppService\stable\2025-05-01\
    • ...but not when it's missing the terminal slash: e.g. C:\git\clones\azure-rest-api-specs\specification\web\resource-manager\Microsoft.Web\AppService\stable\2025-05-01
    • ...this is because NJsonSchema thinks the documentPath is mis-parented.
    • I recommend changing documentPath from a string? to a DirectoryPath? (which also makes it almost self-documenting).
  7. After all of that, I then moved on to my next error:

    System.InvalidOperationException
      HResult=0x80131509
      Message=Could not find the JSON path of a referenced schema: NJsonSchema.JsonSchema,NJsonSchema.JsonSchema. Manually referenced schemas must be added to the 'Definitions' of a parent schema.
      Source=NJsonSchema
      StackTrace:
       at NJsonSchema.JsonPathUtilities.GetJsonPaths(Object rootObject, IEnumerable`1 searchedObjects, IContractResolver contractResolver) in C:\git\forks\NJsonSchema\src\NJsonSchema\JsonPathUtilities.cs:line 65
    • I wasn't able to properly fix this issue, because I wasn't able to fully understand what's going on (e.g. I'll admit I'm still not sure exactly what a "JsonPath" is in this context); the error-message mentions "NJsonSchema.JsonSchema,NJsonSchema.JsonSchema" but I feel that's a bug too...
      • (While debugging, JsonPathUtilities.GetJsonPaths's mappings contained about 2700+ entries; only 2 of which had p.Value == null).
      • My workaround was to simply comment-out the throw new InvalidOperationException - which then allowed NSwagStudio to run to completion.

  • My fixes/workarounds are available in a branch in my clone repo if they're of interest to you or anyone else; Owing to time-constraints I had to introduce other breaking changes and faff-around in the build system and project files in order to build and run the rest of the project locally.

Version of NSwag toolchain, computer and .NET runtime used

The current master HEAD: 2a5ca6e199035833984aa270f059a93e3f513bfe. Issue affects (at least) net462 and net8.0; I did not check with net9.0, net10.0 or netstandard2.0 builds.

To Reproduce

See above.

Expected behavior

No errors and NSwagStudio does not crash.

Additional context

Nothing I can think of right now.


Attachments

  • needs-document-path.json - This is a verbatim copy of the ..._config.json JSON file that NSwagStudio places in my %TEMP% when it runs nswag.exe run tempJsonPath. It also contains the OpenAPI spec as an embedded JSON-in-a-string-in-JSON.

  • has-document-path.json - This is what NSwagStudio produces after I made my changes: it's the same as needs-document-path.json above, except with documentPath set to the original filessystem location of openapi.json on my computer so that the external JSON Schema references can be resolved.

  • Azure-azure-rest-api-specs_Microsoft.Web-AppService-2025-05-01_openapi.json - This is a verbatim copy of Azure's AppServices OpenAPI spec.

  • common-types.zip - This is a verbatim copy of the "$\specification\common-types\" directory which contains the referenced JSON types. It's included for posterity; I recommend simply getting a git checkout 09fee50b88 of azure-rest-api-specs from Azure's repo rather than using these as you'll have to ensure the relative-paths match.