go-kratos/kratos · error
enum %q is not registered
Error message
enum %q is not registered
What it means
Form-binding decoder error for enum-typed fields: protoregistry.GlobalTypes.FindEnumByName(fd.Enum().FullName()) returned protoregistry.NotFound, meaning the enum's Go type is not registered in the binary's global type registry. The decoder needs the registered Go enum (not just the descriptor) to look up value names/numbers, so an unlinked enum type makes every enum value for that field fail with this error.
Source
Thrown at encoding/form/proto_decode.go:169
return fmt.Errorf("parsing map value %q: %w", fd.FullName().Name(), err)
}
mp.Set(key.MapKey(), value)
return nil
}
func parseField(fd protoreflect.FieldDescriptor, value string) (protoreflect.Value, error) {
switch fd.Kind() {
case protoreflect.BoolKind:
v, err := strconv.ParseBool(value)
if err != nil {
return protoreflect.Value{}, err
}
return protoreflect.ValueOfBool(v), nil
case protoreflect.EnumKind:
enum, err := protoregistry.GlobalTypes.FindEnumByName(fd.Enum().FullName())
switch {
case errors.Is(err, protoregistry.NotFound):
return protoreflect.Value{}, fmt.Errorf("enum %q is not registered", fd.Enum().FullName())
case err != nil:
return protoreflect.Value{}, fmt.Errorf("failed to look up enum: %w", err)
}
v := enum.Descriptor().Values().ByName(protoreflect.Name(value))
if v == nil {
i, err := strconv.ParseInt(value, 10, 32) //nolint:mnd
if err != nil {
return protoreflect.Value{}, fmt.Errorf("%q is not a valid value", value)
}
v = enum.Descriptor().Values().ByNumber(protoreflect.EnumNumber(i))
if v == nil {
return protoreflect.Value{}, fmt.Errorf("%q is not a valid value", value)
}
}
return protoreflect.ValueOfEnum(v.Number()), nil
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
v, err := strconv.ParseInt(value, 10, 32) //nolint:mnd
if err != nil {View on GitHub (pinned to 668db92c2c)
Solutions
- Import the generated package containing the enum (even a blank import _ "your/repo/api/enumpkg") so its init() registers the type in GlobalTypes
- Regenerate protobuf code for the API package and make sure the enum file is compiled into this binary (check go.mod replace directives point at the right tree)
- Verify with a tiny test that protoregistry.GlobalTypes.FindEnumByName("pkg.EnumName") succeeds inside the failing binary
- If enums come from a third-party proto, ensure that dependency's Go module is a direct import, not merely transitive
Example fix
// before: enum lookup fails -> enum "api.Status" is not registered import _ "your/repo/api/types" // missing in this binary // after: ensure the generated enum package is imported where binding happens import _ "your/repo/api/types" // registers api.Status via init()
Defensive patterns
Strategy: validation
Validate before calling
// Startup check: all enums referenced by the request types must be registered
func enumsRegistered(msgs ...protoreflect.Message) error {
for _, m := range msgs {
var err error
m.Descriptor().Fields().Range(func(fd protoreflect.FieldDescriptor) bool {
if fd.Kind() == protoreflect.EnumKind {
_, e := protoregistry.GlobalTypes.FindEnumByName(fd.Enum().FullName())
if e != nil {
err = fmt.Errorf("enum %q: %w", fd.Enum().FullName(), e)
return false
}
}
return true
})
if err != nil {
return err
}
}
return nil
} Type guard
func enumRegistered(fullName protoreflect.FullName) bool {
_, err := protoregistry.GlobalTypes.FindEnumByName(fullName)
return !errors.Is(err, protoregistry.NotFound)
} Try / catch
if err := binding.BindQuery(msg, q); err != nil {
if strings.Contains(err.Error(), "is not registered") {
// build/link problem, not user input: fail loudly, no retry
log.Error("enum type missing from binary", "err", err)
return errors.InternalServer("ENUM_NOT_LINKED", err.Error())
}
} Prevention
- Blank-import the generated enum packages in the binary that performs form binding
- Add a unit test asserting FindEnumByName succeeds for every enum your API uses
- Keep generated code and the binary in one module graph; beware go.mod replace forks
- Fail fast at process start (registration smoke test) instead of at first request
When it happens
Trigger: Binding a form/query with a value for an enum field whose generated Go enum package is not linked into the binary: using protoc-generated descriptors via dynamic messages or reflection without importing the generated enum package; enum types registered under a forked/renamed package so FullName lookup misses; code stripped by dead-code elimination in minimal builds (rare in Go, common after generated files are deleted or moved).
Common situations: Mono-repo where the API package with generated enums is only imported by another binary, not this one; switching from static generated types to dynamic descriptors; regenerating protos into a new Go package path and stale registration; shading/renaming packages in CI.
Related errors
- failed to look up enum: %w
- %q is not a valid value
- invalid path: %q is not a message
- field already set for oneof %q
- too many values for field %q: %s
AI-assisted analysis of go-kratos/kratos@668db92c2c (2026-08-16).
Data as JSON: /api/errors/f2e6c3d564c0e3e7.
Report an issue: GitHub.