What are you generating using Kiota, clients or plugins?
API Client/SDK
In what context or format are you using Kiota?
Nuget tool
Client library/SDK language
Csharp
Describe the bug
A component schema that is referenced from an anyOf composed type is generated as an empty class (no properties, empty GetFieldDeserializers/Serialize) whenever the composed reference is traversed before any direct $ref to the same schema. Every later reference, including a direct operation response, reuses the already gutted class.
The trigger is the order in which references are traversed, not the schema itself (as far as I can tell). This is silent as the client compiles, and every response deserializes into AdditionalData with no error or warning.
Expected behavior
Thing is generated with its id, name, and count properties regardless of whether the composed type reference or the direct $ref is encountered first. Reference order in the description should not affect the shape of a generated model.
How to reproduce
Save the openapi.json file in the next section:
Generate: kiota generate -l csharp -d openapi.json -c ReproClient -n Repro -o out
out/Models/Thing.cs has no Id/Name/Count properties:
public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
{
return new Dictionary<string, Action<IParseNode>>
{
};
}
Control: Swap the two operations so post is listed before get, changing nothing else. Thing is then generated correctly with all three properties.
Three runs of each, same machine, same kiota binary:
CONTROL (post / direct $ref listed first): 3, 3, 3 deserializer entries
BUG (get / anyOf listed first): 0, 0, 0 deserializer entries
Open API description file
{
"openapi": "3.0.1",
"info": { "title": "repro", "version": "1.0" },
"paths": {
"/things": {
"get": {
"operationId": "GetTree",
"responses": {
"200": {
"description": "ok",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/TreeResponse" }
}
}
}
}
},
"post": {
"operationId": "CreateThing",
"responses": {
"201": {
"description": "created",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/Thing" }
}
}
}
}
}
}
},
"components": {
"schemas": {
"TreeResponse": {
"type": "object",
"title": "TreeResponse",
"properties": {
"things": {
"title": "Things",
"default": [],
"title": "Things",
"default": [],
"anyOf": [
{ "type": "array", "items": { "$ref": "#/components/schemas/Thing" } },
{ "type": "array", "items": { "type": "object", "additionalProperties": true } }
]
}
}
},
"Thing": {
"type": "object",
"title": "Thing",
"required": ["name"],
"properties": {
"id": { "type": "string", "format": "uuid" },
"name": { "type": "string" },
"count": { "type": "integer" }
}
}
}
}
}
Kiota Version
1.32.2+eb0666c77234695508d65c00ab03827733d87557
Latest Kiota version known to work for scenario above?(Not required)
None known. Also reproduces on 1.34.1.
Known Workarounds
Only spec side ones, both unsatisfying:
- Order the description so a direct
$ref is traversed before the composed reference. Works in the minimal case, but in a real description you don't reliably control traversal order, and it silently regresses when routes are added or reordered.
- Remove the two alternative union, e.g. give the endpoint a distinct response schema so the affected model is never reached through an
anyOf. This is the only robust fix, but it means changing the public API shape to work around a generator bug.
Reordering or renaming the victim schema doesn't help as the problem follows whichever schema is materialized through the composed type first. Redirecting the union at a different schema simply transfers the empty generation to that one.
Configuration
- OS: Ubuntu 24.04.4 LTS
- architecture: x86_64
- kiota: dotnet global tool
- .NET SDK: 8.0.403
Debug output
Click to expand log
```
</details>
### Other information
This looks like the same name based dedup mechanism described in #7791, which was fixed for the `allOf-inheritance-via-nullable-anyOf` path in 1.32.3. That fix does not cover this path as a plain object schema reached through a genuine two alternative union.
I'm fairly certain that this occurs universally on all SDK languages, not just C#.
What are you generating using Kiota, clients or plugins?
API Client/SDK
In what context or format are you using Kiota?
Nuget tool
Client library/SDK language
Csharp
Describe the bug
A component schema that is referenced from an
anyOfcomposed type is generated as an empty class (no properties, emptyGetFieldDeserializers/Serialize) whenever the composed reference is traversed before any direct$refto the same schema. Every later reference, including a direct operation response, reuses the already gutted class.The trigger is the order in which references are traversed, not the schema itself (as far as I can tell). This is silent as the client compiles, and every response deserializes into
AdditionalDatawith no error or warning.Expected behavior
Thing is generated with its
id,name, andcountproperties regardless of whether the composed type reference or the direct$refis encountered first. Reference order in the description should not affect the shape of a generated model.How to reproduce
Save the
openapi.jsonfile in the next section:Generate:
kiota generate -l csharp -d openapi.json -c ReproClient -n Repro -o outout/Models/Thing.cshas noId/Name/Countproperties:Control: Swap the two operations so post is listed before get, changing nothing else. Thing is then generated correctly with all three properties.
Three runs of each, same machine, same kiota binary:
CONTROL(post/ direct$reflisted first): 3, 3, 3 deserializer entriesBUG(get/anyOflisted first): 0, 0, 0 deserializer entriesOpen API description file
Kiota Version
1.32.2+eb0666c77234695508d65c00ab03827733d87557
Latest Kiota version known to work for scenario above?(Not required)
None known. Also reproduces on 1.34.1.
Known Workarounds
Only spec side ones, both unsatisfying:
$refis traversed before the composed reference. Works in the minimal case, but in a real description you don't reliably control traversal order, and it silently regresses when routes are added or reordered.anyOf. This is the only robust fix, but it means changing the public API shape to work around a generator bug.Reordering or renaming the victim schema doesn't help as the problem follows whichever schema is materialized through the composed type first. Redirecting the union at a different schema simply transfers the empty generation to that one.
Configuration
Debug output
Click to expand log
```