Skip to content

Discriminator inside list items not snake-cased with --snake-case-field + --collapse-root-models #3091

@TeaDrinkingProgrammer

Description

@TeaDrinkingProgrammer

Bug report: discriminator inside list items not converted to snake_case

Describe the bug
When using --snake-case-field together with --collapse-root-models, a discriminator
defined on an array's items schema is generated with the original camelCase property
name instead of the converted snake_case field name. This causes Pydantic v2 to raise
a PydanticUserError on import.

This is a partial regression of #1769. The fix there works for discriminators on direct
properties, but not when the discriminator is collapsed from a RootModel wrapping list
items.

To Reproduce

Example schema:

openapi: "3.0.0"
info:
  title: Repro
  version: "1.0"
paths: {}
components:
  schemas:
    FooType:
      type: object
      required: [objectType]
      properties:
        objectType:
          type: string
          enum: [FOO]
    BarType:
      type: object
      required: [objectType]
      properties:
        objectType:
          type: string
          enum: [BAR]
    Container:
      type: object
      properties:
        items:
          type: array
          items:
            discriminator:
              propertyName: objectType
            oneOf:
              - $ref: "#/components/schemas/FooType"
              - $ref: "#/components/schemas/BarType"

Used commandline:

$ datamodel-codegen \
  --input openapi.yaml \
  --input-file-type openapi \
  --output-model-type pydantic_v2.BaseModel \
  --use-annotated \
  --snake-case-field \
  --collapse-root-models \
  --output models.py

Then import the generated file:

$ python -c "import models"

Expected behavior
The generated Container field should use the snake_case field name in the discriminator:

class Container(BaseModel):
    items: (
        list[Annotated[FooType | BarType, Field(discriminator='object_type')]] | None
    ) = None

Importing models.py succeeds.

Actual behavior
The generated discriminator retains the camelCase alias:

class Container(BaseModel):
    items: (
        list[Annotated[FooType | BarType, Field(discriminator='objectType')]] | None
    ) = None

Importing models.py raises:

pydantic.errors.PydanticUserError: Model 'FooType' needs a discriminator field for key 'objectType'

For further information visit https://errors.pydantic.dev/2.12/u/discriminator-no-field

Note: without --collapse-root-models the bug does not occur — the generator wraps
the items in an intermediate RootModel and correctly generates discriminator='object_type' there.

Version:

  • OS: Linux
  • Python version: 3.14.3
  • datamodel-code-generator version: 0.56.1

Additional context
Related to #1769 which fixed discriminators on direct properties. The collapsed
RootModel code path was not covered by that fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions