Repository navigation
An invalid reference is generated for a object that contains two properties of type List<List<string>> (both of the same type). #60381
Copy link
Copy link
Closed
Labels
area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcfeature-openapi
Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
Describe the bug
For the following Type:
using System.ComponentModel;
namespace ManagementApiServer.Models;
public record DynamicTableDataPatch()
{
[Description("List of records to delete. Only the first column (primary key) is considered for deletion.")]
public List<List<string>> Delete { get; set; } = [];
[Description("List of records to add or update.")]
public List<List<string>> AddOrUpdate { get; set; } = [];
}
a wrong (at least neither swagger ui nor scalar can handle it) reference is created for the second occurance of List<List>
OpenApi File To Reproduce
{
"openapi": "3.0.1",
"info": {
"title": "ManagementApiServer | v1",
"version": "1.0.0"
},
"servers": [
{
"url": "https://localhost:7093"
},
{
"url": "http://localhost:5192"
}
],
"paths": {
"/managementApi/v1/dynamicTables/{id}": {
"patch": {
"tags": [
"ManagementApiServer"
],
"description": "Performs an atomic update operation on the specified records, ensuring all changes are applied together or not at all.",
"operationId": "PatchDynamicTable",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DynamicTableDataPatch"
}
}
},
"required": true
},
"responses": {
"204": {
"description": "No Content"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
},
"500": {
"description": "Internal Server Error"
}
}
},
"get": {
"tags": [
"ManagementApiServer"
],
"operationId": "GetDynamicTable",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
],
"responses": {
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
},
"500": {
"description": "Internal Server Error"
},
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
}
}
}
},
"/managementApi/v1/dynamicTables": {
"get": {
"tags": [
"ManagementApiServer"
],
"operationId": "GetDynamicTables",
"responses": {
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
},
"500": {
"description": "Internal Server Error"
},
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/DynamicTable"
}
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"DynamicTable": {
"required": [
"name",
"dynamicTableDefinitionId",
"created",
"modifed"
],
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string"
},
"dynamicTableDefinitionId": {
"type": "string",
"format": "uuid"
},
"description": {
"type": "string"
},
"created": {
"type": "string",
"format": "date-time"
},
"modifed": {
"type": "string",
"format": "date-time"
}
}
},
"DynamicTableDataPatch": {
"type": "object",
"properties": {
"delete": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "string"
}
},
"description": "List of records to delete. Only the first column (primary key) is considered for deletion."
},
"addOrUpdate": {
"type": "array",
"items": {
"$ref": "#/components/schemas/#/properties/delete/items"
},
"description": "List of records to add or update."
}
}
}
},
"securitySchemes": {
"ApiKeyAuth": {
"type": "apiKey",
"description": "Custom authentication header",
"name": "Api-Key",
"in": "header"
}
}
},
"tags": [
{
"name": "ManagementApiServer"
}
]
}
Expected Behavior
Expected behavior
The reference seems invalid.
At least neither scalar nor swagger-ui can handle it.
swagger ui reports a invalid reference.
if i change the second # to the actual Name it works:

Steps To Reproduce
Using a class with List<> seems to result in this wrong reference:
app.MapPatch("/test1234", async ([FromBody] DynamicTableDataPatch records) =>
{
// ....
return Results.NoContent();
})
.Produces(204)
.Produces(403)
.Produces(404)
.Produces(500)
.Accepts<DynamicTableDataPatch>(contentType: "application/json")
.WithOpenApi();
using System.ComponentModel;
namespace ManagementApiServer.Models;
public record DynamicTableDataPatch()
{
[Description("List of records to delete. Only the first column (primary key) is considered for deletion.")]
public List<List<string>> Delete { get; set; } = [];
[Description("List of records to add or update.")]
public List<List<string>> AddOrUpdate { get; set; } = [];
}
Exceptions (if any)
No response
.NET Version
9.0.200
Anything else?
9.0.2 of the nuget package
Metadata
Metadata
Assignees
Labels
area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcfeature-openapi

Activity
dc-davidlazauskas commentedon Feb 14, 2025
+1 also hitting this issue with multiple models where the type is a class rather than a string. It would be nice if the reference (#/components/schemas/#/properties/delete/items) was the same as the first reference (string).
mahald commentedon Feb 17, 2025
emergency fixing it for the time being:
Urganot commentedon Feb 18, 2025
I am also experiencing this error. At least it generates the same wrong stuff in the openapi.json
In my case though I cant find a class that has the same list type twice. For me it happens with a complex type, not with a base type
marcominerva commentedon Feb 18, 2025
This is the same issue of #60012.
captainsafia commentedon Mar 5, 2025
Hey all! Thanks for reporting this issue.
The root cause here (as with many of the other schema related issues) is that the schema generated by STJ's
GetSchemaAsJsonNodeAPI uses relative references if it encounters a type that has already been seen in the type hierarchy before. In the example above, theAddOrUpdateproperty has the same type as theDeleteproperty so STJ "reuses" the schema it generated for the first property via a relative reference.For these scenarios, we need to explode out relative references before passing them into the
OpenApiDocument, which doesn't process relative references well in v1.6 (see microsoft/OpenAPI.NET#2062).This will be resolved for 9.0.x via #60410. For .NET 10 and beyond, we'll be relying on a change in the underlying Microsoft.OpenApi library.
captainsafia commentedon Mar 11, 2025
The bug fix for this has been merged into the servicing branch and will be included in 9.0.4.
daniatic commentedon Mar 27, 2025
@captainsafia is there a prerelease I can use? Were not in production yet, so that would be fine. Or can I use a .net 10 prerelease in the meantime?