micro/go-micro · error
%v argument type not exported: %v
Error message
%v argument type not exported: %v
What it means
During subscriber registration, go-micro's gRPC server validates that every handler method's single argument type is either a builtin or an exported type. If the message type passed to the subscriber method is unexported (e.g. starts with a lowercase letter) the server cannot reliably encode/decode or introspect it, so Subscribe fails with this error instead of registering the subscriber.
Source
Thrown at server/grpc/subscriber.go:153
return fmt.Errorf("subscriber %v returns %v not error", name, returnType.String())
}
} else {
hdlr := reflect.ValueOf(sub.Subscriber())
name := reflect.Indirect(hdlr).Type().Name()
for m := 0; m < typ.NumMethod(); m++ {
method := typ.Method(m)
switch method.Type.NumIn() {
case 3:
argType = method.Type.In(2)
default:
return fmt.Errorf("subscriber %v.%v takes wrong number of args: %v required signature %s",
name, method.Name, method.Type.NumIn(), subSig)
}
if !isExportedOrBuiltinType(argType) {
return fmt.Errorf("%v argument type not exported: %v", name, argType)
}
if method.Type.NumOut() != 1 {
return fmt.Errorf(
"subscriber %v.%v has wrong number of outs: %v require signature %s",
name, method.Name, method.Type.NumOut(), subSig)
}
if returnType := method.Type.Out(0); returnType != typeOfError {
return fmt.Errorf("subscriber %v.%v returns %v not error", name, method.Name, returnType.String())
}
}
}
return nil
}
func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broker.Handler {
return func(p broker.Event) (err error) {
defer func() {View on GitHub (pinned to 24529f1404)
Solutions
- Rename the handler's argument struct to start with an uppercase letter so it is exported
- Move the message type to a shared package and export it
- If the argument is a Go builtin (string, []byte, map, etc.) no change is needed — check that you are not wrapping it in an unexported alias
Example fix
// before
type handler struct{}
func (h *handler) Handle(evt event) error { ... } // 'event' unexported
// after
type Event struct{ ... }
func (h *handler) Handle(evt *Event) error { ... } Defensive patterns
Strategy: validation
Validate before calling
func validSubscriberArg(fn interface{}) bool {
t := reflect.TypeOf(fn)
if t.NumIn() != 3 { return false } // receiver, ctx, msg
arg := t.In(2)
if arg.Kind() == reflect.Ptr { arg = arg.Elem() }
return arg.PkgPath() == "" || arg.Name()[0] >= 'A' && arg.Name()[0] <= 'Z' // builtin or exported
} Prevention
- Always declare subscriber message types as exported structs, typically protobuf-generated types
- Keep the handler signature exactly func(ctx context.Context, msg *T) error
- Write a unit test that calls Subscribe for every subscriber at startup (fail fast on boot)
When it happens
Trigger: Calling server.Subscribe() with a Subscriber whose handler method signature is like `func (s *Handler) handleMsg(msgType)` where `msgType` is an unexported (lowercase) struct type defined in the handler's package.
Common situations: Developers define message structs in a private package or accidentally lowercase the message type name; generated protobuf types are exported but hand-written internal event types often are not.
Related errors
- subscriber %v takes wrong number of args: %v required signat
- subscriber %v argument type not exported: %v
- subscriber %v.%v takes wrong number of args: %v required sig
- subscriber %v has wrong number of outs: %v require signature
- subscriber %v returns %v not error
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/f7978b41715d1f00.
Report an issue: GitHub.