From 52f91680210c02083c45ffb51fecdfde0ffb94f0 Mon Sep 17 00:00:00 2001 From: Onur Cinar Date: Mon, 7 Sep 2026 04:20:29 +0000 Subject: [PATCH] Restore length check for required on empty array/map/slice reflectRequired was purely IsZero()-based, but reflect.Value.IsZero() on a slice only reports true for a nil slice -- a non-nil, zero-length slice/map (e.g. an explicit []string{} or emails: [] in YAML) passed required/@required silently. v1 had a dedicated length check for Array/Map/Slice kinds; restore that behavior so an empty collection is rejected the same way a nil one is. Fixes #285 Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01CgPf2eG8h9xHh7kHFJ4eCs --- required.go | 16 ++++++++++++---- required_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/required.go b/required.go index 977131f..1a2def6 100644 --- a/required.go +++ b/required.go @@ -24,13 +24,21 @@ func Required[T any](value T) (T, error) { return value, err } -// reflectRequired checks if the given value is its zero value. It -// returns an error if the value is zero. +// reflectRequired checks if the given value is its zero value, or an +// empty array, map, or slice. It returns an error if so. func reflectRequired(value reflect.Value) (reflect.Value, error) { var err error - if value.IsZero() { - err = ErrRequired + switch value.Kind() { + case reflect.Array, reflect.Map, reflect.Slice: + if value.Len() == 0 { + err = ErrRequired + } + + default: + if value.IsZero() { + err = ErrRequired + } } return value, err diff --git a/required_test.go b/required_test.go index 9966878..4c7a0b8 100644 --- a/required_test.go +++ b/required_test.go @@ -39,3 +39,43 @@ func TestRequiredMissing(t *testing.T) { t.Fatalf("got unexpected error %v", err) } } + +func TestRequiredEmptySlice(t *testing.T) { + value := []string{} + + _, err := v2.Required(value) + + if !errors.Is(err, v2.ErrRequired) { + t.Fatalf("got unexpected error %v", err) + } +} + +func TestRequiredNonEmptySlice(t *testing.T) { + value := []string{"test"} + + _, err := v2.Required(value) + + if err != nil { + t.Fatal(err) + } +} + +func TestRequiredEmptyMap(t *testing.T) { + value := map[string]string{} + + _, err := v2.Required(value) + + if !errors.Is(err, v2.ErrRequired) { + t.Fatalf("got unexpected error %v", err) + } +} + +func TestRequiredNonEmptyMap(t *testing.T) { + value := map[string]string{"key": "value"} + + _, err := v2.Required(value) + + if err != nil { + t.Fatal(err) + } +}