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

bug: Getting `Bad field type v1.Duration` on v10.15.0+ #1147

Open jonathan-innis opened 11 months ago

jonathan-innis commented 11 months ago

Package version eg. v9, v10:

Error starts occurring on v10.15.0 No errors present on v10.14.1

Issue, Question or Enhancement:

When validating a metav1.Duration struct, we are receiving an error with the validation that we previously never received

  [PANICKED] Test Panicked
  In [It] at: /Users/joinnis/go/pkg/mod/github.com/go-playground/validator/v10@v10.15.0/baked_in.go:2079 @ 08/18/23 00:08:21.25

  Bad field type v1.Duration

  Full Stack Trace
    github.com/go-playground/validator/v10.isGte({0x105ab3970, 0x1400098f680})
        /Users/joinnis/go/pkg/mod/github.com/go-playground/validator/v10@v10.15.0/baked_in.go:2079 +0x440
    github.com/go-playground/validator/v10.hasMinOf({0x105ab3970?, 0x1400098f680?})
        /Users/joinnis/go/pkg/mod/github.com/go-playground/validator/v10@v10.15.0/baked_in.go:2162 +0x24
    github.com/go-playground/validator/v10.wrapFunc.func1({0x1400098f680?, 0x105aba000?}, {0x105ab3970?, 0x1400098f680?})
        /Users/joinnis/go/pkg/mod/github.com/go-playground/validator/v10@v10.15.0/baked_in.go:43 +0x34
    github.com/go-playground/validator/v10.(*validate).traverseField(0x1400098f680, {0x105aafb68, 0x14000190018}, {0x105a726c0?, 0x140001cd680?, 0x14000756868?}, {0x105a7cce0?, 0x140001cd690?, 0x120?}, {0x140000aad00, ...}, ...)
        /Users/joinnis/go/pkg/mod/github.com/go-playground/validator/v10@v10.15.0/validator.go:180 +0xab4
    github.com/go-playground/validator/v10.(*validate).validateStruct(0x1400098f680, {0x105aafb68, 0x14000190018}, {0x105a726c0?, 0x140001cd680?, 0x0?}, {0x105a726c0?, 0x140001cd680?, 0x104c360e8?}, {0x105aba000?, ...}, ...)
        /Users/joinnis/go/pkg/mod/github.com/go-playground/validator/v10@v10.15.0/validator.go:77 +0x51c
    github.com/go-playground/validator/v10.(*Validate).StructCtx(0x140002daa10, {0x105aafb68, 0x14000190018}, {0x105a726c0, 0x140001cd680})
        /Users/joinnis/go/pkg/mod/github.com/go-playground/validator/v10@v10.15.0/validator_instance.go:389 +0x3cc
    github.com/go-playground/validator/v10.(*Validate).Struct(...)
        /Users/joinnis/go/pkg/mod/github.com/go-playground/validator/v10@v10.15.0/validator_instance.go:362
    github.com/aws/karpenter/pkg/apis/settings.Settings.Validate({{0x0, 0x0}, 0x140005a3b48, {0x0, 0x0}, {0x0, 0x0}, {0x0, 0x0}, 0x0, ...})
        /Users/joinnis/github/karpenter/pkg/apis/settings/settings.go:110 +0x138
    github.com/aws/karpenter/pkg/apis/settings.(*Settings).Inject(0x140005b9dc0, {0x105aafbd8, 0x1400075e060}, 0x14000756e38)
        /Users/joinnis/github/karpenter/pkg/apis/settings/settings.go:94 +0x388
    github.com/aws/karpenter/pkg/apis/settings_test.glob..func1.9()
        /Users/joinnis/github/karpenter/pkg/apis/settings/suite_test.go:203 +0xdc

Code sample, to showcase or reproduce:

package main 

type Settings struct {
  d *metav1.Duration
}

func (s Settings) Validate() error {
  return validator.New().Struct(s)
}

func main() {
  s = Settings{d: &metav1.Duration{Duration: time.Second}}
  s.Validate()
}
MysteriousPotato commented 11 months ago

related to #1142

Nested struct validation was not supported in previous version, hence why no error was returned.

However, support extends only to a few tags including the ones that check against zero values such as required and excluded_with. This does not include tags like min.

If you need more complex validation, you must register your own custom tag. Ex.:

func main() {
    type Settings struct {
        D *metav1.Duration `validate:"metamin=15m"`
    }

    v := validator.New()
    if err := v.RegisterValidation("metamin", func(fl validator.FieldLevel) bool {
        duration, ok := fl.Field().Interface().(metav1.Duration)
        if !ok {
            return false
        }

        return v.Var(duration.Duration, "min="+fl.Param()) == nil
    }); err != nil {
        panic(err)
    }

    // valid
    s1 := Settings{&metav1.Duration{time.Minute * 15}}
    if err := v.Struct(s1); err != nil {
        panic(err)
    }

    // invalid
    s2 := Settings{&metav1.Duration{time.Minute * 14}}
    if err := v.Struct(s2); err != nil {
        panic(err)
    }
}

Also, it's worth noting that struct fields must be exported in order for them to get validated.

deankarn commented 11 months ago

Is this the code you're having an issue with? https://github.com/aws/karpenter/blob/a87ed30c8e60d6be25ce10fb058ad66c6174edab/pkg/apis/settings/settings.go#L57

Example doesn't clearly demonstrate an issue.

deankarn commented 11 months ago

@jonathan-innis can we consolidate the conversation here :) https://github.com/go-playground/validator/issues/1142