fix: nil-pointer panic from custom type function

A DecodeCustomTypeFunc returning nil to mean "leave this pointer
field unset" panicked in reflect.Value.Set, since reflect.ValueOf(nil)
is the invalid zero Value. Guard against a nil return before Set.

This is the panic from #68/#69: the earlier fix routed pointer fields
through the generic Ptr recursion instead of guarding nil, which
discarded a custom function's own populated pointer result and had
to be reverted. Guarding val == nil directly fixes the panic without
touching the case that broke.
This commit is contained in:
dualfroz committed 2026-09-04 08:15:15 +02:00
1 parent 3b027bdc88
commit 8a7336f727
3 files changed
+147

No files matched your search

+31
View File
@@ -1881,6 +1881,37 @@ func TestDecoder_RegisterCustomTypeFunc(t *testing.T) {
Equal(t, v.Slice, []customString{"customv1", "customv2"})
}
func TestDecoder_CustomTypeFuncPointerNilValue(t *testing.T) {
type User struct {
Name string
}
type TestStruct struct {
U *User `form:"u"`
}
d := NewDecoder()
d.RegisterCustomTypeFunc(func(vals []string) (interface{}, error) {
if vals[0] == "" {
// Signals "leave the field at its zero value" for an absent input,
// this must not panic even though the field itself is a pointer.
return nil, nil
}
return &User{Name: vals[0]}, nil
}, &User{})
var empty TestStruct
err := d.Decode(&empty, url.Values{"u": {""}})
Equal(t, err, nil)
Equal(t, empty.U, nil)
var populated TestStruct
err = d.Decode(&populated, url.Values{"u": {"bob"}})
Equal(t, err, nil)
NotEqual(t, populated.U, nil)
Equal(t, populated.U.Name, "bob")
}
func TestDecoder_EmptyArrayString(t *testing.T) {
type T1 struct {
F1 string `form:"F1"`