Title: x-go-type on a schema with allOf is silently ignored; first member's x-go-type leaks through instead · Issue #2335 · oapi-codegen/oapi-codegen · GitHub
Open Graph Title: x-go-type on a schema with allOf is silently ignored; first member's x-go-type leaks through instead · Issue #2335 · oapi-codegen/oapi-codegen
X Title: x-go-type on a schema with allOf is silently ignored; first member's x-go-type leaks through instead · Issue #2335 · oapi-codegen/oapi-codegen
Description: Summary When a schema has both allOf and x-go-type, the x-go-type directive on the schema itself is silently ignored. Worse, if any allOf member has its own x-go-type, that override leaks through and becomes the alias target for the oute...
Open Graph Description: Summary When a schema has both allOf and x-go-type, the x-go-type directive on the schema itself is silently ignored. Worse, if any allOf member has its own x-go-type, that override leaks through a...
X Description: Summary When a schema has both allOf and x-go-type, the x-go-type directive on the schema itself is silently ignored. Worse, if any allOf member has its own x-go-type, that override leaks through a...
Opengraph URL: https://github.com/oapi-codegen/oapi-codegen/issues/2335
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"x-go-type on a schema with allOf is silently ignored; first member's x-go-type leaks through instead","articleBody":"## Summary\n\nWhen a schema has both `allOf` and `x-go-type`, the `x-go-type` directive on the schema itself is silently ignored. Worse, if any `allOf` member has its own `x-go-type`, that override leaks through and becomes the alias target for the outer schema — producing a nonsensical alias that drops fields the user expects.\n\nThis was originally surfaced as an overlay issue in https://github.com/oapi-codegen/oapi-codegen/pull/2087, but the bug is **unrelated to overlays**. Overlays merely make it easy to add `x-go-type` to a third-party spec; the same misbehavior reproduces with a hand-edited spec containing no overlay at all.\n\n## Reproduction\n\nSpec:\n\n```yaml\ncomponents:\n schemas:\n Client:\n x-go-type: OverlayClient\n type: object\n required: [name]\n properties:\n name: { type: string }\n ClientWithId:\n x-go-type: OverlayClientWithId\n allOf:\n - $ref: '#/components/schemas/Client'\n - properties:\n id: { type: integer }\n required: [id]\n```\n\nUser-provided Go types `OverlayClient{Name}` and `OverlayClientWithId{Id, Name}`.\n\nExpected output:\n\n```go\ntype Client = OverlayClient\ntype ClientWithId = OverlayClientWithId\n```\n\nActual output:\n\n```go\ntype Client = OverlayClient\ntype ClientWithId = OverlayClient // wrong\n```\n\nPR #2087 contains a runnable demonstration in `examples/anyof-allof-oneof/`.\n\n## Root cause\n\nThere are two compounding bugs.\n\n**(1) `pkg/codegen/schema.go:335-342`** — The `allOf` branch in `GenerateGoSchema` returns before the `x-go-type` check at line 344:\n\n```go\nif schema.AllOf \\!= nil {\n mergedSchema, err := MergeSchemas(schema.AllOf, path)\n ...\n return mergedSchema, nil // early return; x-go-type never consulted\n}\n\n// Check x-go-type, which will completely override the definition ...\nif extension, ok := schema.Extensions[extPropGoType]; ok { ... }\n```\n\nThe code comment explicitly states `x-go-type` \"will completely override the definition of this schema\" — this contract is violated when the outer schema uses `allOf`.\n\n**(2) `pkg/codegen/merge_schemas.go:113-116`** — `mergeOpenapiSchemas` unions extensions from both sides without filtering out Go-specific directives:\n\n```go\nresult.Extensions = make(map[string]any, len(s1.Extensions)+len(s2.Extensions))\nmaps.Copy(result.Extensions, s1.Extensions)\nmaps.Copy(result.Extensions, s2.Extensions)\n```\n\nSo `Client`'s `x-go-type: OverlayClient` is copied into the merged schema's extensions. `mergeSchemas` then recursively calls `GenerateGoSchema` on the merged schema (line 62), which this time has no `AllOf`, hits the `x-go-type` branch, and emits `type ClientWithId = OverlayClient`.\n\n## Version\n\nReproduced on `main` as of PR #2087 (commit f64f92b).","author":{"url":"https://github.com/mromaszewicz","@type":"Person","name":"mromaszewicz"},"datePublished":"2026-04-23T18:04:36Z","url":"https://github.com/oapi-codegen/oapi-codegen/issues/2335"}
| react-profiling | 0 |
| react-import-map | react,react-dom,react-dom/client,react-dom/profiling,react-is,react-reconciler,react/compiler-runtime,react/jsx-dev-runtime,react/jsx-runtime,scheduler@d5750093facf |
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:f7246257-b173-84e6-466f-b647d5bf47a0 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 96B2:CF7A5:172B504:1E8BE71:6AF9CA62 |
| html-safe-nonce | cfc4e1edd910c6b46c5eb252d264cc03baa6032e13a1ba09a0ed58e3000e47b2 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI5NkIyOkNGN0E1OjE3MkI1MDQ6MUU4QkU3MTo2QUY5Q0E2MiIsInZpc2l0b3JfaWQiOiI4NTkzMDYwNTU2ODkyMTI5ODkwIiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | 14c6a7805b308dcb3bc49b19708f34b269de5d4daac96c5ee9a6b9a209217dc9 |
| hovercard-subject-tag | issue:4317885661 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/oapi-codegen/oapi-codegen/2335/issue_layout |
| twitter:image | https://opengraph.githubassets.com/308d4cc4a85a4f608fa28cc27b1c5619959d308f96a9f8bf88aa7798fd3a89f2/oapi-codegen/oapi-codegen/issues/2335 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/308d4cc4a85a4f608fa28cc27b1c5619959d308f96a9f8bf88aa7798fd3a89f2/oapi-codegen/oapi-codegen/issues/2335 |
| og:image:alt | Summary When a schema has both allOf and x-go-type, the x-go-type directive on the schema itself is silently ignored. Worse, if any allOf member has its own x-go-type, that override leaks through a... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | mromaszewicz |
| hostname | github.com |
| expected-hostname | github.com |
| None | 612d3e6ffd693e7ea8d9fcf452370995872baef31d825b1fedef704cd3d24ac7 |
| turbo-cache-control | no-preview |
| go-import | github.com/oapi-codegen/oapi-codegen git https://github.com/oapi-codegen/oapi-codegen.git |
| octolytics-dimension-user_id | 142752710 |
| octolytics-dimension-user_login | oapi-codegen |
| octolytics-dimension-repository_id | 173009358 |
| octolytics-dimension-repository_nwo | oapi-codegen/oapi-codegen |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 173009358 |
| octolytics-dimension-repository_network_root_nwo | oapi-codegen/oapi-codegen |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 072e34035c13c31543fba9f025cbbbda4210dae4 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
| react-app-name | issues |
Links:
Viewport: width=device-width