OpenAPITools / OpenAPITools/openapi-generator

[BUG] Bug Report / Feature Request: Improve oneOf Handling for FastAPI/Pydantic

Open
#21,985 0 comments 8 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Issue: Bug
Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

I am facing a similar issue:

🐞 Bug Report / Feature Request: Improve oneOf Handling for FastAPI/Pydantic
Summary:
The current OpenAPI Generator implementation for Python (FastAPI + Pydantic) generates wrapper classes for oneOf schemas (e.g., CaseEmbeddingsInputPayloadCaseInformation) that rely on a field like actual_instance and custom deserialization logic. However, this structure is incompatible with FastAPI's request parsing flow and Pydantic's native validation pipeline, leading to broken or non-functional schema resolution.

{
  "title": "Case Embeddings Input",
  "type": "object",
  "required": ["case_information"],
  "properties": {
    "case_information": {
      "oneOf": [
        {
          "$ref": "./case_information_with_case_number.json"
        },
        {
          "$ref": "./case_information_with_id_v2.json"
        }
      ]
    }
  }
}

and my individual schemas are:

{
  "title": "Case Information with case number",
  "type": "object",
  "required": [
    "partner_id",
    "case_number",
    "case_category",
    "case_description"
  ],
  "properties": {
    "partner_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 30,
      "description": "Partner Id"
    },
    "case_number": {
      "type": "string",
      "minLength": 1,
      "maxLength": 30,
      "description": "Case Id"
    },
    "id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 30,
      "description": "Case Id",
      "nullable": true
    },
    "case_category": {
      "type": "string",
      "minLength": 1,
      "maxLength": 5000,
      "description": "Case Category"
    },
    "case_description": {
      "type": "string",
      "minLength": 1,
      "maxLength": 5000,
      "description": "Case Description"
    },
    "case_language_identifier": {
      "type": "string",
      "minLength": 1,
      "maxLength": 10,
      "description": "Case Language Identifier"
    }
  }
}

Schema 2

{
  "title": "Case Information with id",
  "type": "object",
  "required": [
    "partner_id",
    "id",
    "case_category",
    "case_description"
  ],
  "properties": {
    "partner_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 30,
      "description": "Partner Id"
    },
    "case_number": {
      "type": "string",
      "minLength": 1,
      "maxLength": 30,
      "description": "Case Id",
      "nullable": true
    },
    "id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 30,
      "description": "Case Id"
    },
    "case_category": {
      "type": "string",
      "minLength": 1,
      "maxLength": 5000,
      "description": "Case Category"
    },
    "case_description": {
      "type": "string",
      "minLength": 1,
      "maxLength": 5000,
      "description": "Case Description"
    },
    "case_language_identifier": {
      "type": "string",
      "minLength": 1,
      "maxLength": 10,
      "description": "Case Language Identifier"
    }
  }
}

which produces

class CaseEmbeddingsInputPayload(BaseModel):
    case_information: Optional[CaseEmbeddingsInputPayloadCaseInformation] = None

Where CaseEmbeddingsInputPayloadCaseInformation wraps the oneOf logic using an actual_instance field and custom init() or from_json() methods.
However:

  • FastAPI does not invoke init() or from_json() during request parsing.
  • The payload is passed as keyword arguments, which do not match the expected structure.
  • As a result, actual_instance is never set, and validation fails silently. unless we manually set {"actual_instance": **kwargs"} in the init def.
  • The input ends up being None, even though it matches one of the schemas.

Instead of generating a wrapper class, emit a native Python Union type:

class CaseEmbeddingsInputPayload(BaseModel):
    case_information: Union[CaseInformationWithCaseNumber, CaseInformationWithIdV2]

which works.

Originally posted by @lek18 in #21892

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No repository files or tests are named. Start by tracing the generated CaseEmbeddingsInputPayloadCaseInformation wrapper, especially actual_instance, init(), and from_json(), alongside the FastAPI request parsing path. Done means oneOf fields are generated as native Python Union types and valid requests pass Pydantic validation without manual actual_instance handling.

Written by the indexing model from the issue text.

Assessment

Tech stack
fastapi, python
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.