Description
After upgrading from swagger-annotations 2.2.43 to 2.2.45, the generated OpenAPI 3.1.0 spec contains spurious JSON Schema keywords (additionalProperties, contains, unevaluatedItems, items) with "default": "##default" sentinel values on response schemas where they do not belong. This is related to the sentinel change in #5063 (v2.2.44) and the partial fix in #5078 (v2.2.45), but v2.2.45 does not fully resolve the issue.
This is distinct from #5086 (which covers @Parameter + @ArraySchema). This bug affects response body schemas — both $ref schemas and type: array schemas.
Environment
- Spring Boot: 3.5.11
- springdoc-openapi: 2.8.16
- swagger-annotations: 2.2.45 (regression confirmed absent in 2.2.43)
- OpenAPI version: 3.1.0
Reproduction
A standard Spring Boot controller returning a List<T>:
@GetMapping("/v1/items/{item-id}/details")
public ResponseEntity<List<ItemDetailResponse>> getDetails(
@PathVariable("item-id") String itemId) {
// ...
}
With swagger-annotations 2.2.43, the generated schema for the 200 response is:
{
"type": "array",
"items": {
"$ref": "#/components/schemas/ItemDetailResponse"
}
}
With swagger-annotations 2.2.45, the same endpoint produces:
{
"type": "array",
"additionalProperties": {
"default": "##default"
},
"contains": {
"default": "##default"
},
"items": {
"$ref": "#/components/schemas/ItemDetailResponse",
"contains": {
"default": "##default"
},
"default": "##default",
"unevaluatedItems": {
"default": "##default"
}
},
"unevaluatedItems": {
"default": "##default"
}
}
Similarly, endpoints returning a single object via $ref gain extraneous keywords:
{
"$ref": "#/components/schemas/SomeResponse",
"additionalProperties": {
"default": "##default"
},
"contains": {
"default": "##default"
},
"default": "##default",
"items": {
"default": "##default"
},
"unevaluatedItems": {
"default": "##default"
}
}
Scale of impact
In our production spec (~250 endpoint Spring Boot service), upgrading to 2.2.45 introduces:
| Keyword |
Spurious occurrences with ##default |
default |
1,375 |
contains |
246 |
unevaluatedItems |
246 |
additionalProperties |
242 |
items |
241 |
Why this breaks downstream tools
The combination of type: array + additionalProperties is semantically invalid — additionalProperties is an object-only keyword. Code generators like Fabrikt interpret additionalProperties as a signal that the schema represents a map/dictionary. When combined with type: array, this creates an impossible type (array + MAP specialization), causing a crash:
java.lang.IllegalStateException: Unknown OAS type: array and format: null
and specialization: MAP
Root cause hypothesis
The ##default sentinel introduced in #5063 is not being filtered out in all code paths before schema serialization. PR #5078 addressed the defaultValue merge logic, but the sentinel is still leaking through the sub-schema keywords (additionalProperties, contains, unevaluatedItems, items) that get populated with { "default": "##default" } objects when they should not be present at all.
Expected behavior
Response schemas should not contain any ##default sentinel values or spurious sub-schema keywords that were not explicitly defined in the source annotations. The output with 2.2.45 should match the clean output from 2.2.43.
Workaround
Pin swagger-annotations to 2.2.43.
Description
After upgrading from
swagger-annotations2.2.43 to 2.2.45, the generated OpenAPI 3.1.0 spec contains spurious JSON Schema keywords (additionalProperties,contains,unevaluatedItems,items) with"default": "##default"sentinel values on response schemas where they do not belong. This is related to the sentinel change in #5063 (v2.2.44) and the partial fix in #5078 (v2.2.45), but v2.2.45 does not fully resolve the issue.This is distinct from #5086 (which covers
@Parameter+@ArraySchema). This bug affects response body schemas — both$refschemas andtype: arrayschemas.Environment
Reproduction
A standard Spring Boot controller returning a
List<T>:With
swagger-annotations2.2.43, the generated schema for the 200 response is:{ "type": "array", "items": { "$ref": "#/components/schemas/ItemDetailResponse" } }With
swagger-annotations2.2.45, the same endpoint produces:{ "type": "array", "additionalProperties": { "default": "##default" }, "contains": { "default": "##default" }, "items": { "$ref": "#/components/schemas/ItemDetailResponse", "contains": { "default": "##default" }, "default": "##default", "unevaluatedItems": { "default": "##default" } }, "unevaluatedItems": { "default": "##default" } }Similarly, endpoints returning a single object via
$refgain extraneous keywords:{ "$ref": "#/components/schemas/SomeResponse", "additionalProperties": { "default": "##default" }, "contains": { "default": "##default" }, "default": "##default", "items": { "default": "##default" }, "unevaluatedItems": { "default": "##default" } }Scale of impact
In our production spec (~250 endpoint Spring Boot service), upgrading to 2.2.45 introduces:
##defaultdefaultcontainsunevaluatedItemsadditionalPropertiesitemsWhy this breaks downstream tools
The combination of
type: array+additionalPropertiesis semantically invalid —additionalPropertiesis an object-only keyword. Code generators like Fabrikt interpretadditionalPropertiesas a signal that the schema represents a map/dictionary. When combined withtype: array, this creates an impossible type (array+MAPspecialization), causing a crash:Root cause hypothesis
The
##defaultsentinel introduced in #5063 is not being filtered out in all code paths before schema serialization. PR #5078 addressed thedefaultValuemerge logic, but the sentinel is still leaking through the sub-schema keywords (additionalProperties,contains,unevaluatedItems,items) that get populated with{ "default": "##default" }objects when they should not be present at all.Expected behavior
Response schemas should not contain any
##defaultsentinel values or spurious sub-schema keywords that were not explicitly defined in the source annotations. The output with 2.2.45 should match the clean output from 2.2.43.Workaround
Pin
swagger-annotationsto 2.2.43.