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

  1. Change the field type to string (or a named string type).
  2. If the value is stored as bytes, add a string field or convert with string(b) and validate with Var.
  3. For uuid.UUID-like types, either validate with the `uuid` tag on a string representation or write a custom validator.
  4. 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

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


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