OpenAPI 3.0 export emits invalid `type: "null"` for nullable $ref properties (regression, Aug 2026)
Seunggi KIM
Summary
When a project is exported as OpenAPI 3.0, every property that is a nullable $ref comes out with "type": "null" as a sibling of the combinator, instead of the OpenAPI 3.0 form nullable: true.
Scalar nullable properties in the same export are still written correctly as "nullable": true, so a single exported document ends up internally inconsistent — two different encodings for the same concept in one file.
This is a regression. The same project, exported with identical request parameters, produced "nullable": true for these properties until mid-August 2026.
Actual output
"someRefField": {
"allOf": [
{ "$ref": "#/components/schemas/SomeDto" }
],
"type": "null"
}
Expected output (OpenAPI 3.0)
"someRefField": {
"allOf": [
{ "$ref": "#/components/schemas/SomeDto" }
],
"nullable": true
}
Why the current output is invalid
It is not valid under either specification version:
- The exported document declares "openapi": "3.0.1", and OpenAPI 3.0 has no null type at all. Nullability in 3.0 is expressed only with nullable: true. Since $ref cannot have siblings in 3.0, the documented pattern is exactly allOf + nullable: true — which is what the export used to produce.
- It is not valid as OpenAPI 3.1 / JSON Schema either. A scalar "type": "null" placed next to allOf asserts "the value must be null and must validate against SomeDto", which nothing can satisfy. In 3.1 this has to be f": "..."}, {"type": "null"}]} or{"type": ["object", "null"]} — or, if a combinator is used, the {"type": "null"} must be a
member of the allOf array, not
So the output is neither the 3.0 form that was requested nor a well-formed 3.1 form.
Scope within one exported document
In a single export of one project
- scalar properties, encoded "nullable": true — 273
- $ref-composed properties, encod
The split follows the $ref-compos nullable $ref property is affected
and no scalar property is. That ie one specific code path in the3.0 exporter rather than a project authoring issue.
For comparison, in the last cleant there were 58 $ref-composednullable properties and all of them were written as "nullable": true.
Regression window
- Export taken 2026-08-10 — 0 occurrences of "type": "null"
- Export taken 2026-08-25, ~09:40
Nothing changed on our side betwe project, same export endpoint,
same request body, same oasVersioopenapi": "3.0.1".
How it was exported
Via the Open API export endpoint:
- POST /v1/projects/{projectId}/e
- header X-Apidog-Api-Version: 2024-03-28
- body:
{
"scope": { "type": "ALL" },
"options": {
"includeApidogExtensionProperties": true,
"addFoldersToTags": false
},
"oasVersion": "3.0",
"exportFormat": "JSON"
}
Note that oasVersion is explicitly "3.0", so a 3.1-only construct should not appear in the response at all. It would be worth checking whether the UI path (Settings → Export Data →
OpenAPI 3.0) is affected in the s
Steps to reproduce
- Define a schema SomeDto (objec
- Define a schema Parent with a references SomeDto and is marked
nullable.
- Export the project as OpenAPI the UI.
- Inspect components.schemas.Parent.properties.someRefField.
Downstream impact
This is not a cosmetic differencehe specification, ignore the
invalid sibling type, and therefoon-nullable. When the API then
legitimately returns null for thaent throws while deserializing.
For us this reached production: ant from an affected export, every
user hitting the normal "no recornt triggered a deserialization
error, until we traced it back toe server was returning exactly what
its own schema promised — only thong.
We checked one widely used generart, v1.44.3) against four encodings
of the same nullable $ref. Only ts mishandled:
- {"allOf": [$ref], "type": "nullrated non-nullable (incorrect)
- {"nullable": true, "allOf": [$ref]} — previous export → generated nullable (correct)
- {"allOf": [$ref, {"type": "null"}]} → generated nullable (correct)
- {"anyOf": [$ref, {"type": "null(correct)
The generator is behaving correctly in all four cases; the input is the problem.
Suggested fix
When oasVersion is 3.0, emit nullombinator for nullable $ref
properties — consistent with how are already exported in the samedocument.
When exporting 3.1, emit the nullnyOf, or a type array) rather than
as a sibling of a combinator.
Workaround for anyone else hitting this
Post-process the exported documenenerator:
jq 'walk(
if (type == "object")
and (.type? == "null")
and (has("allOf") or has("on
then del(.type) + {nullable: true}
else .
end
)' export.json > normalized.json
This rewrites only the offending st of the document byte-identical.