Skip to content

Propagate external refs into allOf#2299

Open
mromaszewicz wants to merge 1 commit intooapi-codegen:mainfrom
mromaszewicz:fix/issue-2288
Open

Propagate external refs into allOf#2299
mromaszewicz wants to merge 1 commit intooapi-codegen:mainfrom
mromaszewicz:fix/issue-2288

Conversation

@mromaszewicz
Copy link
Copy Markdown
Member

Closes: #2288

When allOf references an external schema, valueWithPropagatedRef was only rewriting direct property $refs to include the remote file path. Nested refs — array items, additionalProperties, and sub-object properties — were left as local "#/..." refs, producing unqualified Go type names that fail to compile.

Extract the propagation logic into a recursive propagateRemoteRefs function that walks Properties, Items, and AdditionalProperties, rewriting any local ref it finds. This ensures types like *[]externalRef0.Role are correctly qualified instead of the broken *[]Role.

Extend the externalref test with a User/Role/EnrichedUser scenario that exercises the array-items case from the issue report.

@mromaszewicz mromaszewicz requested a review from a team as a code owner March 23, 2026 19:21
@mromaszewicz
Copy link
Copy Markdown
Member Author

@greptileai

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 23, 2026

Greptile Summary

This PR fixes a bug where allOf extending an external schema would leave nested #/... refs (array items, additionalProperties, and sub-object properties) unqualified, producing broken Go type names like *[]Role instead of *[]externalRef0.Role. The fix extracts the existing per-property ref-rewriting into a new recursive propagateRemoteRefs helper and extends it to cover Items and AdditionalProperties, then adds a concrete User/Role/EnrichedUser regression test that exercises the array-items case from the reported issue.

  • pkg/codegen/merge_schemas.go: Refactors valueWithPropagatedRef to call a new propagateRemoteRefs function that recursively walks Properties, Items, and AdditionalProperties, rewriting any local #/... ref to include the remote file path.
  • internal/test/externalref/packageB/spec.yaml: Adds Role (string enum) and User (object with a roles: []Role array property) to supply the external types for the regression test.
  • internal/test/externalref/packageA/spec.yaml: Adds EnrichedUser as an allOf extension of the external User, reproducing issue allOf with cross-file does not qualify nested type references from source schema #2288.
  • Gap to be aware of: propagateRemoteRefs does not yet walk AnyOf, OneOf, AllOf, or Not sub-schemas. External types that use those composition keywords internally with local refs could trigger the same class of bug in a follow-up scenario.

Confidence Score: 4/5

  • Safe to merge; correctly fixes the reported array-items qualification bug with a targeted regression test.
  • The core logic is correct and the fix is well-scoped to the reported issue. The only gap is that AnyOf/OneOf/AllOf/Not sub-schema refs are not yet walked, which could resurface the same class of bug for schemas using those keywords — but that is a follow-up concern, not a regression from this PR.
  • pkg/codegen/merge_schemas.go — consider extending propagateRemoteRefs to cover AnyOf/OneOf/AllOf/Not in a follow-up.

Important Files Changed

Filename Overview
pkg/codegen/merge_schemas.go Extracts inline property-ref propagation into a recursive propagateRemoteRefs helper that also walks Items and AdditionalProperties; correctly fixes the reported issue but does not cover AnyOf/OneOf/AllOf/Not sub-schema refs.
internal/test/externalref/packageA/spec.yaml Adds EnrichedUser schema that extends the external User type via allOf, reproducing the cross-file array-items ref qualification bug from issue #2288; missing newline at end of file (pre-existing).
internal/test/externalref/packageB/spec.yaml Adds Role enum and User object (with a roles: []Role array) to packageB's spec, providing the external types needed to exercise the fix.

Reviews (1): Last reviewed commit: "Propagate external refs into allOf" | Re-trigger Greptile

@mromaszewicz mromaszewicz added the bug Something isn't working label Mar 23, 2026
@cdevienne
Copy link
Copy Markdown

cdevienne commented Mar 26, 2026

I tested your patch with the following files, which is an extract of a bigger api in which I encountered the same issue.

cfg-api.yaml:

package: api
output: api.gen.go
generate:
  models: true
output-options:
  # to make sure that all types are generated
  skip-prune: true
import-mapping:
  ./types.yaml: "types"

api.yaml:

components:
  schemas:
    CustomerStatusPostPayloadV1:
      allOf:
        - $ref: './types.yaml#/components/schemas/CustomerStatusV1'
        - type: object
          properties:
            name:
              type: string

types.yaml

components:
  schemas:
    CustomerStatusEnum:
      type: string
      enum:
        - Approved
        - Disputed
        - Suspended

    CustomerStatusV1:
      allOf:
        - type: object
          properties:
            status:
              $ref: '#/components/schemas/CustomerStatusEnum'

The generated files still doesn't reference the enum properly:

// Package api provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.6.0 DO NOT EDIT.
package api

// CustomerStatusPostPayloadV1 defines model for CustomerStatusPostPayloadV1.
type CustomerStatusPostPayloadV1 struct {
	Name   *string             `json:"name,omitempty"`
	Status *CustomerStatusEnum `json:"status,omitempty"`
}

When an external schema is flattened via allOf, local #/... refs nested
within properties, items, additionalProperties, and composition keywords
(allOf, anyOf, oneOf, not) must be rewritten to include the remote
component path. Without this, generated Go code references unqualified
types that don't exist in the local package.

Extracts ref-rewriting into a recursive propagateRemoteRefs helper and
extends it to walk the full schema tree.

Fixes oapi-codegen#2288

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@mromaszewicz
Copy link
Copy Markdown
Member Author

@cdevienne , thanks for this example. I'm very minimalist with this code because this aggregate schema traversal is so fragile. Could you see if this latest PR works for you? I've reproduced your test case in our unit tests, and it failed before my changes, and passes after.

@cdevienne
Copy link
Copy Markdown

@mromaszewicz Tested it, it works!

I have another similar issue though, will report it separately.

Thanks a lot

@cdevienne
Copy link
Copy Markdown

Just in case, the similar issue I got is: #2308

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

allOf with cross-file does not qualify nested type references from source schema

2 participants