micro/go-micro · error
rpc.Handle: type ${name} is not exported
Error message
rpc.Handle: type ${name} is not exported What it means
Handle was called with a handler whose Name() is non-empty but not exported (does not start with an uppercase letter). The router only registers exported names so they can be addressed by external clients; unexported names are rejected at registration time.
Source
Thrown at server/rpc_router.go:465
func (router *router) NewHandler(h interface{}, opts ...HandlerOption) Handler {
return NewRpcHandler(h, opts...)
}
func (router *router) Handle(h Handler) error {
router.mu.Lock()
defer router.mu.Unlock()
if router.serviceMap == nil {
router.serviceMap = make(map[string]*service)
}
if len(h.Name()) == 0 {
return errors.New("rpc.Handle: handler has no name")
}
if !isExported(h.Name()) {
return errors.New("rpc.Handle: type " + h.Name() + " is not exported")
}
rcvr := h.Handler()
s := new(service)
s.typ = reflect.TypeOf(rcvr)
s.rcvr = reflect.ValueOf(rcvr)
// check name
if _, present := router.serviceMap[h.Name()]; present {
return errors.New("rpc.Handle: service already defined: " + h.Name())
}
s.name = h.Name()
s.method = make(map[string]*methodType)
// Install the methods
for m := 0; m < s.typ.NumMethod(); m++ {
method := s.typ.Method(m)View on GitHub (pinned to 24529f1404)
Solutions
- Change the handler name to start with an uppercase letter (e.g. "Calculator")
- If the name comes from config, update it to an exported-style identifier
- When deriving names from Go types, use an exported type or map to an explicit exported name
Example fix
// before
router.NewHandler(NewCalcService("calculator"))
// after
router.NewHandler(NewCalcService("Calculator")) Defensive patterns
Strategy: validation
Validate before calling
name := h.Name()
if name == "" || !unicode.IsUpper(rune(name[0])) {
return fmt.Errorf("service name %q must be exported (start with uppercase)", name)
}
router.NewHandler(h) Try / catch
if err := router.NewHandler(h); err != nil {
if strings.Contains(err.Error(), "is not exported") {
return fmt.Errorf("fix service name for %T: %w", h, err)
}
return err
} Prevention
- Use PascalCase identifiers for all service names
- Never derive service names directly from unexported Go types without renaming
- Add a startup check that all registered service names begin with an uppercase letter
When it happens
Trigger: Registering a handler named e.g. "calculator" or "_internal"; generating service names from Go type names of unexported types.
Common situations: Auto-deriving the service name from an unexported Go struct type; lowercase name strings in config files; renaming a service to a lowercase identifier during refactoring.
Related errors
- rpc Register: type ${sname} is not exported
- rpc.Handle: handler has no name
- go.micro.client
- streamer not implemented
- connection header set to close
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/419362834814e262.
Report an issue: GitHub.