Skip to content

Nullable $ref property (anyOf/oneOf with type: null) is silently omitted from the generated type #950

Closed as duplicate

Description

@paulyii

Summary

A property declared as a nullable reference — anyOf: [{$ref: …}, {type: "null"}] — is silently omitted from the generated Swift struct. No warning, no error, no diagnostic of any kind. The build succeeds and the property simply does not exist.

The same happens with the oneOf spelling. Sibling properties on the same schema generate normally, so the failure is per-property and easy to miss.

This is the standard shape FastAPI/Pydantic emits for an Optional[SomeModel] field, so it is not an exotic construct.

Reproduction

Minimal OpenAPI 3.1 document:

{
  "openapi": "3.1.0",
  "info": { "title": "Repro", "version": "1.0.0" },
  "paths": {
    "/thing": {
      "get": {
        "operationId": "getThing",
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Thing" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Nested": {
        "type": "object",
        "properties": { "name": { "type": "string" } },
        "required": ["name"]
      },
      "Thing": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "plain_nullable": { "type": ["string", "null"] },
          "ref_nullable_anyof": {
            "anyOf": [{ "$ref": "#/components/schemas/Nested" }, { "type": "null" }]
          },
          "ref_nullable_oneof": {
            "oneOf": [{ "$ref": "#/components/schemas/Nested" }, { "type": "null" }]
          },
          "ref_plain": { "$ref": "#/components/schemas/Nested" }
        },
        "required": ["id"]
      }
    }
  }
}

Config:

generate:
  - types
  - client
accessModifier: public

Expected

Thing has five properties, with the nullable references generated as optionals of Components.Schemas.Nested.

Actual

Thing has three. Both nullable-reference properties are gone:

public struct Thing: Codable, Hashable, Sendable {
    public var id: Swift.Int
    public var plain_nullable: Swift.String?
    public var ref_plain: Components.Schemas.Nested?
}

ref_nullable_anyof and ref_nullable_oneof are absent, and absent from CodingKeys too. plain_nullable (type-array nullability) and ref_plain (non-nullable $ref) both generate correctly — so the trigger is specifically reference + null.

Versions

Reproduced identically on 1.12.2 and 1.13.1, via the SPM build-tool plugin, Xcode 26, generating for an iOS target.

Workaround

Inlining the referenced schema in place of the $ref, with "type": ["object", "null"], generates the property correctly (as a nested …Payload type). That costs the shared named type at the embedding site, but it is the only shape we found that works. Rewriting anyOf → oneOf does not help.

Impact

The silence is the real problem. We shipped a hand-written workaround — an extra list fetch plus normalized-string matching — to reconstruct an object the API had been sending all along, because the generated type simply had no field for it. That went unnoticed for about two months. A diagnostic would have turned this into a five-minute fix.

Even if generating these is out of scope for now, emitting a warning for a property that is being dropped would prevent the silent-data-loss failure mode.

Activity

  1. simonjbeaumont commented on Sep 20, 2026

    @simonjbeaumont
    Collaborator

    A diagnostic would have turned this into a five-minute fix.

    Even if generating these is out of scope for now, emitting a warning for a property that is being dropped would prevent the silent-data-loss failure mode.

    I thought we emitted diagnostics for everything we skip?

    Are you confident there was no diagnostic?

  2. czechboy0 commented on Sep 20, 2026

    @czechboy0
    Contributor

    Hi @paulyii,

    a friendly reminder of our CONTRIBUTING policy: https://github.com/apple/swift-openapi-generator/blob/main/CONTRIBUTING.md#ai-tools

    All human-facing communication, such as issues, PR descriptions, and comments must be written by humans and not LLMs.

    Please make sure to follow this policy in future interactions on this repo, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions