OpenAPITools / OpenAPITools/openapi-generator
[BUG] [Go] Discriminator unmarshal error & why DisallowUnknownFields() should be removed
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 (example)?
- 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
The change introduced in #17267 added a call to DisallowUnknownFields() on the Go JSON decoder to reject unknown fields. This unintentionally broke JSON unmarshalling in generated code that uses Go struct embedding.
Why? When using struct embedding, the embedded struct's UnmarshalJSON(data []byte) error method receives the full JSON object, including fields from its parent. Due to DisallowUnknownFields(), any unknown parent fields will cause unmarshalling to fail.
In the case of the Go generator, I found that the issue occurs when using discriminators. See the steps to reproduce below.
I'm very surprised that this critical bug has remained unnoticed for over a year.
openapi-generator version
v7.12.0
Steps to reproduce
Use the spec file:
modules/openapi-generator/src/test/resources/3_0/go/allof_multiple_ref_and_discriminator.yaml
and the corresponding generated code:
samples/client/others/go/allof_multiple_ref_and_discriminator.
To reproduce the issue:
- Add a new test file
issue_test.goinsamples/client/others/go/allof_multiple_ref_and_discriminatorwith the following content:
package openapi
import (
"encoding/json"
"fmt"
"testing"
)
func TestUnmarshalFinalItem(t *testing.T) {
jsonStr := `{
"prop1": "example",
"quantity": 10,
"unitPrice": 5.5,
"totalPrice": 55.0,
"title": "example",
"type": "FINAL"
}`
var item FinalItem
err := json.Unmarshal([]byte(jsonStr), &item)
if err != nil {
t.Fatalf("Unmarshal error: %v", err)
}
fmt.Printf("Unmarshalled FinalItem: %+v\n", item)
}
- Run the tests with:
go test
You will observe the following error:
--- FAIL: TestUnmarshalFinalItem (0.00s)
issue_test.go:22: Unmarshal error: json: unknown field "prop1"
The error is caused by the DisallowUnknownFields() inside the embedded struct UnmarshalJSON(data []byte) (err error) function:
https://github.com/curvegrid/openapi-generator/blob/afc27ef4bc969f07613807aba51ec1a9f46cf605/samples/client/others/go/allof_multiple_ref_and_discriminator/model_base_item.go#L138
Suggest a fix
It is not because additionalProperties is set to false in the OpenAPI spec that a generated client should completely fail if the server returns extra fields. In real-world APIs, it is common for servers to evolve and add new properties over time.
The use of DisallowUnknownFields() in generated client code is extremely dangerous because:
- It prevents clients from tolerating new fields added to the server response, making clients extremely fragile.
- It breaks backward compatibility: older clients interacting with newer servers will crash when they encounter unexpected fields.
- It fundamentally contradicts robust client design principles, where clients should ignore unknown fields rather than fail.
I would propose to remove DisallowUnknownFields() from the Go client templates as soon as possible to restore proper resilience and compatibility when dealing with evolving APIs (and embedded structs).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with modules/openapi-generator/src/test/resources/3_0/go/allof_multiple_ref_and_discriminator.yaml and the generated sample in samples/client/others/go/allof_multiple_ref_and_discriminator. Read model_base_item.go around its UnmarshalJSON method, then run the described go test reproduction. Done means discriminator-based FinalItem unmarshalling accepts the parent fields without the unknown-field error and the regression is covered by a test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- api
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100