diff --git a/internal/libyaml/structmeta.go b/internal/libyaml/structmeta.go index 70c66309..c1b8cc12 100644 --- a/internal/libyaml/structmeta.go +++ b/internal/libyaml/structmeta.go @@ -157,7 +157,11 @@ func getStructInfo(st reflect.Type) (*structInfo, error) { if len(fields) > 1 { for _, flag := range fields[1:] { switch flag { - case "omitempty": + case "omitempty", "omitzero": + // omitzero is Go 1.24's encoding/json flag. yaml's + // omitempty already drops zero values (including structs), + // so treat omitzero as the same to avoid panicking on + // structs that share tags with json. info.OmitEmpty = true case "flow": info.Flow = true diff --git a/omitzero_test.go b/omitzero_test.go new file mode 100644 index 00000000..f7e93cb8 --- /dev/null +++ b/omitzero_test.go @@ -0,0 +1,45 @@ +// Copyright 2025 The go-yaml Project Contributors +// SPDX-License-Identifier: Apache-2.0 + +package yaml_test + +import ( + "testing" + + "go.yaml.in/yaml/v4" +) + +func TestUnmarshalOmitZeroFlag(t *testing.T) { + type T struct { + A string `yaml:"a,omitzero"` + B int `yaml:"b,omitzero"` + } + var v T + if err := yaml.Unmarshal([]byte("a: hi\nb: 2\n"), &v); err != nil { + t.Fatal(err) + } + if v.A != "hi" || v.B != 2 { + t.Fatalf("got %+v", v) + } +} + +func TestMarshalOmitZeroFlag(t *testing.T) { + type T struct { + A string `yaml:"a,omitzero"` + B int `yaml:"b,omitzero"` + } + out, err := yaml.Marshal(T{}) + if err != nil { + t.Fatal(err) + } + if string(out) != "{}\n" { + t.Fatalf("got %q", out) + } + out, err = yaml.Marshal(T{A: "hi", B: 2}) + if err != nil { + t.Fatal(err) + } + if string(out) != "a: hi\nb: 2\n" { + t.Fatalf("got %q", out) + } +}