Skip to content

default_factory wraps empty dict default with inner union RootModel instead of dict #3061

@ilovemesomeramen

Description

@ilovemesomeramen

Describe the bug
When a field's type is object (dict) with additionalProperties containing an anyOf union that includes a tuple-like array schema (prefixItems + minItems/maxItems), and the field has "default": {}, the generator wraps the default with the inner union member's RootModel instead of using default_factory=dict.

Generated: default_factory=lambda: Configs({}) where Configs is a RootModel[tuple[Any]]
Expected: default_factory=dict

The {} default belongs to the outer dict type, not to the inner Configs RootModel.

To Reproduce

Example schema:

{
  "openapi": "3.1.0",
  "info": { "title": "Repro", "version": "0.1.0" },
  "paths": {
    "/test": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/MyModel" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "MyModel": {
        "type": "object",
        "properties": {
          "configs": {
            "additionalProperties": {
              "anyOf": [
                {
                  "prefixItems": [{}],
                  "type": "array",
                  "maxItems": 1,
                  "minItems": 1
                },
                { "type": "number" }
              ]
            },
            "type": "object",
            "default": {}
          }
        }
      }
    }
  }
}

Used commandline:

$ datamodel-codegen --input schema.json --output models.py --output-model-type pydantic_v2.BaseModel --use-annotated --field-constraints

Generated output:

class Configs(RootModel[tuple[Any]]):
    root: Annotated[tuple[Any], Field(max_length=1, min_length=1)]

class MyModel(BaseModel):
    configs: Annotated[
        dict[str, Configs | float] | None,
        Field(
            default_factory=lambda: Configs({}),
            description='Mapping of name to config',
            title='Configs',
        ),
    ]

Expected behavior
The default factory should match the field's outer type (dict), not the inner union member:

class MyModel(BaseModel):
    configs: Annotated[
        dict[str, Configs | float] | None,
        Field(
            default_factory=dict,
            description='Mapping of name to config',
            title='Configs',
        ),
    ]

Version:

  • OS: Linux
  • Python version: 3.13
  • datamodel-code-generator version: 0.55.0

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