go-playground / validator

:100:Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving
MIT License
16.14k stars 1.29k forks source link

non-validate Custum Field Types cause panic: reflect: call of reflect.Value.Type on zero Value #1155

Closed DSK-KOYAMA closed 10 months ago

DSK-KOYAMA commented 10 months ago

Package version eg. v9, v10:

v10.15.2

Issue, Question or Enhancement:

panic: reflect: call of reflect.Value.Type on zero Value

goroutine 1 [running]:
reflect.Value.typeSlow({0x0?, 0x0?, 0xc0003d75d8?})
        /usr/lib/go-1.20/src/reflect/value.go:2610 +0x12e
reflect.Value.Type(...)
        /usr/lib/go-1.20/src/reflect/value.go:2605
github.com/go-playground/validator/v10.(*validate).traverseField(0xc0003f8000, {0x60ea08, 0xc0000a8010}, {0x5a1b00?, 0xc0003d75c0?, 0x110?}, {0x5a5a00?, 0xc0003d75d8?, 0x7f44bd73feb8?}, {0xc0003bc780, ...}, ...)
        /home/xxxxxx/go/pkg/mod/github.com/go-playground/validator/v10@v10.15.2/validator.go:177 +0xb4b
github.com/go-playground/validator/v10.(*validate).validateStruct(0xc0003f8000, {0x60ea08, 0xc0000a8010}, {0x5a1b00?, 0xc0003d75c0?, 0x40e64a?}, {0x5a1b00?, 0xc0003d75c0?, 0x28?}, {0x610fe0, ...}, ...)
        /home/xxxxxx/go/pkg/mod/github.com/go-playground/validator/v10@v10.15.2/validator.go:77 +0x750
github.com/go-playground/validator/v10.(*Validate).StructCtx(0xc0003f3a40, {0x60ea08, 0xc0000a8010}, {0x5a1b00, 0xc0003d75c0?})
        /home/xxxxxx/go/pkg/mod/github.com/go-playground/validator/v10@v10.15.2/validator_instance.go:393 +0x479
github.com/go-playground/validator/v10.(*Validate).Struct(...)
        /home/xxxxxx/go/pkg/mod/github.com/go-playground/validator/v10@v10.15.2/validator_instance.go:366
main.main()
        /home/xxxxxx/tmp/val/main.go:31 +0x2c7

Code sample, to showcase or reproduce:

From Custom Field Types Line 15 -- change validate tag to comment

package main

import (
  "database/sql"
  "database/sql/driver"
  "fmt"
  "reflect"

  "github.com/go-playground/validator/v10"
)

// DbBackedUser User struct
type DbBackedUser struct {
  Name sql.NullString `validate:"required"`
  Age  sql.NullInt64  //`validate:"required"`
}

// use a single instance of Validate, it caches struct info
var validate *validator.Validate

func main() {

  validate = validator.New()

  // register all sql.Null* types to use the ValidateValuer CustomTypeFunc
  validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{})

  // build object for validation
  x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}}

  err := validate.Struct(x)

  if err != nil {
    fmt.Printf("Err(s):\n%+v\n", err)
  }
}

// ValidateValuer implements validator.CustomTypeFunc
func ValidateValuer(field reflect.Value) interface{} {

  if valuer, ok := field.Interface().(driver.Valuer); ok {

    val, err := valuer.Value()
    if err == nil {
      return val
    }
    // handle the error how you want
  }

  return nil
}
deankarn commented 10 months ago

@DSK-KOYAMA thank you for the report, this should not be resolved in release https://github.com/go-playground/validator/releases/tag/v10.15.3 to fix this regression.