go-playground/validator · error
Bad field type %T
Error message
Bad field type %T
What it means
The `urn_rfc8141` validator parses the field as a URN per RFC 8141 using the github.com/leodido/go-urn package. It only supports reflect.Kind String; for any other kind it panics with `Bad field type %T` (formatted with field.Interface(), so the dynamic Go type is shown). This is a programming-error panic: the tag is on a field that cannot hold a URN string.
Source
Thrown at baked_in.go:1716
// isUrnRFC8141 is the validation function for validating if the current field's value is a valid URN as per RFC 8141.
func isUrnRFC8141(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.String:
str := field.String()
if str == "" {
return false
}
_, match := urn.Parse([]byte(str), urn.WithParsingMode(urn.RFC8141Only))
return match
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
// isUrnRFC2141 is the validation function for validating if the current field's value is a valid URN as per RFC 2141.
func isUrnRFC2141(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.String:
str := field.String()
_, match := urn.Parse([]byte(str))
return match
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}View on GitHub (pinned to facf128d2e)
Solutions
- Change the field type to string (or a named string type).
- If the value is stored as bytes, add a string field or convert with string(b) and validate with Var.
- For uuid.UUID-like types, either validate with the `uuid` tag on a string representation or write a custom validator.
- Avoid `interface{}`-typed fields carrying tags; type them concretely as string.
Example fix
// before
type Resource struct {
URN [64]byte `validate:"urn_rfc8141"` // panics: Bad field type [64]uint8
}
// after
type Resource struct {
URN string `validate:"urn_rfc8141"` // e.g. "urn:isbn:0451450523"
} Defensive patterns
Strategy: type-guard
Validate before calling
s, ok := any(field).(string)
if !ok {
return fmt.Errorf("urn_rfc8141 requires string, got %T", field)
}
if _, match := urn.Parse([]byte(s), urn.WithParsingMode(urn.RFC8141Only)); !match {
return fmt.Errorf("not a valid RFC 8141 URN: %s", s)
} Type guard
func asURNString(v any) (string, bool) {
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.String { return "", false }
return rv.String(), true
} Try / catch
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("urn_rfc8141 panic (non-string field): %v", r)
}
}() Prevention
- Keep URNs in string fields; convert []byte buffers to string before validation
- Do not put tags on interface{} fields
- Use v.Var(string(data), "urn_rfc8141") for byte-slice values
When it happens
Trigger: Tagging non-string fields with `validate:"urn_rfc8141"`, e.g. `Urn [32]byte`, `Identifier uuid.UUID`, `URN any`. The %T verb in the panic makes it identifiable: it prints e.g. `Bad field type [32]uint8`.
Common situations: Storing URNs in byte arrays fixed-size buffers from C interop or protobuf; identifier fields typed as uuid.UUID where the developer wanted a URN-format check; interface{} fields in generic config containers.
Related errors
- panic(err) (os.Stat *PathError re-raised for unexpected stat
- Bad param number for required_if %s
- Duplicate param %s for required_if %s
- Bad param number for excluded_if %s
- Bad param number for required_unless %s
AI-assisted analysis of go-playground/validator@facf128d2e (2026-09-02).
Data as JSON: /api/errors/036d915b3acd88ec.
Report an issue: GitHub.