OpenAPITools / OpenAPITools/openapi-generator

[BUG] [Go] Discriminator unmarshal error & why DisallowUnknownFields() should be removed

Open
#21,164 7 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Issue: Bug
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:

  1. Add a new test file issue_test.go in samples/client/others/go/allof_multiple_ref_and_discriminator with 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)
}
  1. 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

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 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.