go-playground/validator · error

err.Error() from strconv.ParseBool

Error message

err.Error() from strconv.ParseBool

What it means

util.go:317 panicIf converts any error returned by strconv.ParseInt/ParseUint/ParseFloat/ParseBool into a panic whose message is simply err.Error(). It backs the asInt/asUint/asFloat32/asFloat64/asBool helpers that evaluate numeric comparison parameters in tags like `min`, `max`, `gt`, `len`. A panic here means the numeric (or boolean) parameter inside a struct tag is malformed, e.g. `min=abc`.

Source

Thrown at util.go:317

// or panics if it can't convert
func asFloat32(param string) float64 {
	i, err := strconv.ParseFloat(param, 32)
	panicIf(err)
	return i
}

// asBool returns the parameter as a bool
// or panics if it can't convert
func asBool(param string) bool {
	i, err := strconv.ParseBool(param)
	panicIf(err)

	return i
}

func panicIf(err error) {
	if err != nil {
		panic(err.Error())
	}
}

// Checks if field value matches regex. If fl.Field can be cast to Stringer, it uses the Stringer interfaces
// String() return value. Otherwise, it uses fl.Field's String() value.
func fieldMatchesRegexByStringerValOrString(regexFn func() *regexp.Regexp, fl FieldLevel) bool {
	regex := regexFn()
	switch fl.Field().Kind() {
	case reflect.String:
		return regex.MatchString(fl.Field().String())
	default:
		if stringer, ok := getValue(fl.Field()).(fmt.Stringer); ok {
			return regex.MatchString(stringer.String())
		} else {
			return regex.MatchString(fl.Field().String())
		}
	}
}

View on GitHub (pinned to facf128d2e)

Solutions

  1. Find the struct tag with the failing parameter and correct the numeric/boolean literal (use '.' as the decimal separator).
  2. When generating tags dynamically, validate/normalize parameters with strconv.ParseInt yourself before building the tag string.
  3. Ensure numeric comparison tags are applied to fields whose tag expects a numeric param (min/max/len/gt/lt/gte/lte) and pass plain integers.
  4. Add a unit test that constructs each dynamically-generated tag once at startup so the panic surfaces in tests, not production.
  5. If parameters come from config/env, pre-validate them with a small parse step and fail fast with a clear message.

Example fix

// before
minParam := cfg.MinSize // "1,5"
tag := fmt.Sprintf("gte=%s", minParam)

// after
n, err := strconv.ParseFloat(strings.ReplaceAll(cfg.MinSize, ",", "."), 64)
if err != nil {
    return fmt.Errorf("invalid min size %q", cfg.MinSize)
}
tag := fmt.Sprintf("gte=%v", n)
Defensive patterns

Strategy: validation

Validate before calling

func validateTagParam(kind, p string) error {
    var err error
    switch kind {
    case "int":
        _, err = strconv.ParseInt(p, 10, 64)
    case "float":
        _, err = strconv.ParseFloat(p, 64)
    case "bool":
        _, err = strconv.ParseBool(p)
    }
    return err
}

Try / catch

func safeValidate(v *validator.Validate, s interface{}) (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("malformed tag parameter: %v", r)
        }
    }()
    return v.Struct(s)
}

Prevention

When it happens

Trigger: Using a numeric tag with a non-numeric or out-of-range parameter: `validate:"min=10x"`, `len=,` , `gtfield=` missing value, `validate:"gtefield=NonNumericField"` is fine but `max=1e999` (range) panics; a boolean-parse path triggered by a tag that expects true/false receiving garbage; dynamically generated tags with an empty or nil parameter string.

Common situations: Hand-written tags with typos in the numeric constant; tags built at runtime via fmt.Sprintf where a variable is empty or formatted wrong (e.g. locale decimal comma `min=1,5`); copying tags that used different parameter semantics; environment-driven configuration values interpolated into tags without sanitization.

Related errors


AI-assisted analysis of go-playground/validator@facf128d2e (2026-09-02). Data as JSON: /api/errors/bb02d30f9a426ced. Report an issue: GitHub.