Skip to content

field: Schema | None = None should generate anyOf where null is the last item #1027

Closed

Description

@sobolevn

Hi 👋

I am using msgspec to generate JsonSchema for my schemas in wemake-services/django-modern-rest#990

But, there's a big difference with how msgspec and pydantic generates schema for this type:

class _TailsSchema(pydantic.BaseModel):
    id: int
    name: str

class _UserCreateModel(pydantic.BaseModel):
    tails: _TailsSchema | None = None

vs

class _TailsSchema(msgspec.Struct):
    id: int
    name: str

class _UserCreateModel(msgspec.Struct):
    tails: _TailsSchema | None = None

What schema is generated

pydantic:

"_UserCreateModel": {
  "properties": {
    "tails": {
      "anyOf": [
        {
          "$ref": "#/components/schemas/_TailsSchema"
        },
        {
          "type": "null"
        }
      ]
    },
    // ...
}

msgspec:

"_UserCreateModel": {
  "properties": {
    "tails": {
      "anyOf": [
        {
          "type": "null"
        },
        {
          "$ref": "#/components/schemas/_TailsSchema"
        }
      ]
    },
    // ...
}

The final result from msgspec makes Swagger to render

{
  "email": "string",
  "tail": null,
  "tail_optional": null
}

as the example value, which is correct, but less ideal than the pydantic's version:

{
  "email": "string",
  "tail": {
    "id": 0,
    "name": "string"
  },
  "tail_optional": {
    "id": 0,
    "name": "string"
  }
}

Looks like that Swagger just takes the first value from anyOf, it would be reasonable to change the order. It would also be more semantically similar to how Schema | None is used in Python, not None | Schema

Activity

  1. added a commit that references this issue on Jul 9, 2026
    e1c6f23
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