Skip to content

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

@dahu33

Description

@dahu33

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions