GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix: resolve Go field name collisions when JSON keys differ only by separator (#2495) by rifkir23 · Pull Request #2550 · oapi-codegen/oapi-codegen

Conversation

@rifkir23

@rifkir23 rifkir23 commented Sep 3, 2026

Copy link
Copy Markdown

Problem

When two JSON properties in the same object differ only by their separator — e.g. host-fqdn and host_fqdn — both normalize to the same Go field name HostFqdn, producing a redeclared in this block compile error in the generated code. - is not a valid Go identifier character so stripping it is unavoidable, and _ folds to the same PascalCase, so the two collide.

This is reproducible against real specs (the issue references the Tenable Vulnerability Management API, whose info object contains both host-fqdn and host_fqdn).

Fixes #2495

Fix

Resolve Go field-name collisions within a struct in GenFieldsFromProperties. The first property to claim a name keeps it; each later property that would collide gets an incrementing numeric suffix (HostFqdn, HostFqdn2, HostFqdn3, ...), re-checked so a suffixed name cannot itself collide. This matches the direction suggested in the issue ("suffix numbers on colliding fields") and is consistent with the collision-resolution the codebase already does elsewhere (enum constants, type names).

Only the Go identifier changes — the JSON struct tag still uses the original JsonFieldName, so the wire format is unchanged and round-trips exactly as before. Explicit x-go-name overrides continue to work and take precedence.

Tests

Added TestGenFieldsFromProperties_ResolvesGoFieldNameCollisions: two properties (host-fqdn, host_fqdn) now generate HostFqdn and HostFqdn2 with their original JSON tags preserved. Verified the test FAILS without the fix (both fields render as HostFqdn, matching the reported compile error) and PASSES with it. Full pkg/codegen suite passes; gofmt and go vet are clean.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

greptile-apps[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@rifkir23
rifkir23 requested a review from a team as a code owner September 3, 2026 13:21
@greptile-apps

greptile-apps Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds numeric disambiguation for object properties whose JSON names normalize to the same Go field identifier while preserving their original wire tags.

  • Adds a property-level collision-resolution pass in schema generation.
  • Adds a unit test for two separator-differing property names.
  • The resolved names are not propagated to custom serialization helpers, and the resolver does not reserve the synthetic AdditionalProperties field.

Confidence Score: 3/5

This PR should not merge until collision-resolved names are shared with serialization boilerplate and synthetic struct fields are included in collision handling.

Colliding properties can now compile into structs whose generated marshal/unmarshal methods access the wrong field, while an AdditionalProperties property can still produce an uncompilable duplicate declaration.

Files Needing Attention: pkg/codegen/schema.go and the union/additional-properties boilerplate templates

Important Files Changed

Filename Overview
pkg/codegen/schema.go Adds field-name disambiguation, but the resolved identifiers diverge from serialization boilerplate and omit a synthetic-field collision.
pkg/codegen/schema_test.go Covers the basic two-property declaration and JSON-tag case but not additional-properties or union boilerplate paths.
Prompt To Fix All With AI
### Issue 1
pkg/codegen/schema.go:1657-1661
**Boilerplate uses unresolved field names**

When a union or additional-properties object contains properties such as `host-fqdn` and `host_fqdn`, the struct declares the latter as `HostFqdn2`, but generated marshal/unmarshal templates still resolve both accesses as `HostFqdn`, causing the second JSON property to read from or write to the wrong Go field.

### Issue 2
pkg/codegen/schema.go:1779-1784
**Synthetic field collision remains**

When an object allows additional properties and also declares a property named `additionalProperties` or uses `x-go-name: AdditionalProperties`, the resolver does not reserve the synthetic field name, so `GenStructFromSchema` emits two `AdditionalProperties` fields and the generated Go code fails to compile.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix: resolve Go field name collisions wh..." | Re-trigger Greptile

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

greptile-apps[bot]
greptile-apps Bot reviewed Sep 3, 2026
View reviewed changes
Comment thread pkg/codegen/schema.go Outdated
Comment on lines +1657 to +1661
goFieldNames := resolveFieldNameCollisions(props)
for i, p := range props {
field := ""

goFieldName := p.GoFieldName()
goFieldName := goFieldNames[i]

@greptile-apps greptile-apps Bot Sep 3, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Boilerplate uses unresolved field names

When a union or additional-properties object contains properties such as host-fqdn and host_fqdn, the struct declares the latter as HostFqdn2, but generated marshal/unmarshal templates still resolve both accesses as HostFqdn, causing the second JSON property to read from or write to the wrong Go field.

Knowledge Base Used: Schema and Go model generation

Prompt To Fix With AI
This is a comment left during a code review.
Path: pkg/codegen/schema.go
Line: 1657-1661

Comment:
**Boilerplate uses unresolved field names**

When a union or additional-properties object contains properties such as `host-fqdn` and `host_fqdn`, the struct declares the latter as `HostFqdn2`, but generated marshal/unmarshal templates still resolve both accesses as `HostFqdn`, causing the second JSON property to read from or write to the wrong Go field.

**Knowledge Base Used:** [Schema and Go model generation](https://app.greptile.com/oapi-codegen/-/custom-context/knowledge-base/oapi-codegen/oapi-codegen/-/docs/schema-and-model-generation.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread pkg/codegen/schema.go Outdated
Comment on lines +1779 to +1784
seen := make(map[string]struct{}, len(props))
for i, p := range props {
name := p.GoFieldName()
if _, exists := seen[name]; exists {
for n := 2; ; n++ {
candidate := fmt.Sprintf("%s%d", name, n)

@greptile-apps greptile-apps Bot Sep 3, 2026

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Synthetic field collision remains

When an object allows additional properties and also declares a property named additionalProperties or uses x-go-name: AdditionalProperties, the resolver does not reserve the synthetic field name, so GenStructFromSchema emits two AdditionalProperties fields and the generated Go code fails to compile.

Knowledge Base Used:

  • Schema and Go model generation
  • Name shared path parameter helpers safely
Prompt To Fix With AI
This is a comment left during a code review.
Path: pkg/codegen/schema.go
Line: 1779-1784

Comment:
**Synthetic field collision remains**

When an object allows additional properties and also declares a property named `additionalProperties` or uses `x-go-name: AdditionalProperties`, the resolver does not reserve the synthetic field name, so `GenStructFromSchema` emits two `AdditionalProperties` fields and the generated Go code fails to compile.

**Knowledge Base Used:**
- [Schema and Go model generation](https://app.greptile.com/oapi-codegen/-/custom-context/knowledge-base/oapi-codegen/oapi-codegen/-/docs/schema-and-model-generation.md)
- [Name shared path parameter helpers safely](https://app.greptile.com/oapi-codegen/-/custom-context/knowledge-base/oapi-codegen/oapi-codegen/-/reverts/revert_2476-20260716-shared-path-parameter-collision-bd52535.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@rifkirr23
fix: resolve Go field name collisions when JSON keys differ only by s…
c1eb68a
…eparator (oapi-codegen#2495)

Move collision resolution from GenFieldsFromProperties to a single-source
resolver (ResolvePropertyGoFieldNameCollisions) that populates an unexported
resolvedGoFieldName on each Property. GoFieldName() now returns the resolved
name, so the struct declaration AND the generated marshal/unmarshal boilerplate
(union, additional-properties templates) all share the same disambiguated
field name. Also reserves the synthetic AdditionalProperties field name so a
real property named 'additionalProperties' does not collide with it.

Fixes oapi-codegen#2495
@rifkir23
rifkir23 force-pushed the fix/field-name-collision-hyphen-underscore branch from ba4b9de to c1eb68a Compare September 3, 2026 15:35
@rifkir23

rifkir23 commented Sep 3, 2026

Copy link
Copy Markdown
Author

thanks for the careful review, both points were valid. i reworked the fix so it is a single source of truth instead of only touching the struct declaration:

  • collision resolution now runs once per schema (ResolvePropertyGoFieldNameCollisions) and stores the disambiguated name on the property. GoFieldName() returns it, so the struct declaration and the generated marshal/unmarshal boilerplate (union and additional-properties templates, which all read GoFieldName) now use the same name. this fixes the "boilerplate reads the wrong field" case.
  • the resolver reserves the synthetic AdditionalProperties field name first, so a real property named additionalProperties (or one using x-go-name: AdditionalProperties) is suffixed instead of producing a duplicate declaration.

added a test for the additional-properties reservation case as well. full pkg/codegen suite and the rest of ./... pass, gofmt and vet clean.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

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

Reviewers

@greptile-apps greptile-apps[bot] greptile-apps[bot] left review comments

At least 1 approving review is required to merge this pull request.

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

oapi-codegen v2 produces duplicate Go field names when JSON keys differ only by separator (hyphen vs underscore)

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@rifkir23 @rifkirr23
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.