OpenAPITools / OpenAPITools/openapi-generator

[BUG] Inline request-body schema silently overwrites a spec-defined schema with a mangled-equal name

Open
#24,548 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Bug Report Checklist
  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

An inline request-body schema can silently overwrite a schema declared in components.schemas,
deleting its properties from the generated code. There is no error and no warning — the generated
client simply has the wrong contract for an endpoint that never used an inline schema in the first place.

InlineModelResolver.uniqueName() compares candidate names by raw string only. But generators mangle
schema names before emitting types, so the inline schema importMembers_request and the spec-defined
ImportMembersRequest both become the model ImportMembersRequest. The raw keys differ, no collision is
detected, and one model ends up replacing the other.

openapi-generator version

7.25.0-SNAPSHOT, built from master at commit 4aed9c1c635.

OpenAPI declaration file content or url
openapi: 3.0.3
info: { title: t, version: 1.0.0 }
paths:
  /members/import:
    post:
      operationId: importMembers          # inline body -> "importMembers_request"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                inlineOnly: { type: string }
      responses: { "200": { description: ok } }
  /members/echo:
    post:
      operationId: echoMembers
      requestBody:
        content:
          application/json:
            schema: { $ref: "#/components/schemas/ImportMembersRequest" }
      responses: { "200": { description: ok } }
components:
  schemas:
    ImportMembersRequest:                 # mangles to the same model name
      properties:
        declaredFieldA: { type: string }
        declaredFieldB: { type: integer }
Generation Details
java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generate \
  -i spec.yaml -g typescript-fetch -o out

typescript-fetch is only used for a short reproduction — the collision happens in
InlineModelResolver, so this is generator-agnostic (it reproduces the same way for Java, Spring, etc.).

Steps to reproduce
  1. Save the spec above as spec.yaml
  2. Run the command above
  3. Look at out/models/

Actual output

Only one model file is produced, and it has the inline schema's properties:

out/models/
├── ImportMembersRequest.ts
└── index.ts
// ImportMembersRequest.ts
export interface ImportMembersRequest {
    inlineOnly?: string;      // <- the inline body schema won
}

declaredFieldA and declaredFieldB are gone. /members/echo, which explicitly $refs
ImportMembersRequest, now serialises the wrong shape. Exit code is 0; nothing is logged.

Expected output

Two distinct models — the spec-defined one untouched, and the inline one under a non-colliding name:

// ImportMembersRequest.ts
export interface ImportMembersRequest {
    declaredFieldA?: string;
    declaredFieldB?: number;
}
// ImportMembersRequest1.ts
export interface ImportMembersRequest1 {
    inlineOnly?: string;
}
Suggest a fix

https://github.com/OpenAPITools/openapi-generator/blob/4aed9c1c635/modules/openapi-generator/src/main/java/org/openapitools/codegen/InlineModelResolver.java#L919-L932

if (!openAPI.getComponents().getSchemas().containsKey(uniqueName) && !uniqueNames.contains(uniqueName)) {
    return uniqueName;
}

The check is exact-string. Making it normalization-aware (ignore separators and case, i.e. compare the
way the name will look after mangling) turns this into a detected collision, and the existing
name + "_" + count fallback then keeps both models.

I have a patch with a regression test ready and will open a PR shortly.

Related issues/PRs

Searched open and closed issues/PRs for uniqueName, InlineModelResolver collisions, and inline schemas
overwriting components; I could not find an existing report of this specific mangling collision.

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

Start with InlineModelResolver.java around lines 919-932, then run the provided spec with the typescript-fetch generation command. Confirm the collision produces one model, and use the reported regression scenario to verify that the declared schema remains intact while the inline schema receives a distinct name.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, openapi, typescript
Domain
api, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.