micro/go-micro · error
subscriber %v argument type not exported: %v
Error message
subscriber %v argument type not exported: %v
What it means
validateSubscriber reflects on the subscriber function's message argument and requires its type to be exported (or a builtin). The gRPC server must construct and decode values of this type from incoming wire messages, and unexported types defined inside another package cannot be instantiated or named by the codec, so registration fails.
Source
Thrown at server/grpc/subscriber.go:128
endpoints: endpoints,
opts: options,
}
}
func validateSubscriber(sub server.Subscriber) error {
typ := reflect.TypeOf(sub.Subscriber())
var argType reflect.Type
if typ.Kind() == reflect.Func {
name := "Func"
switch typ.NumIn() {
case 2:
argType = typ.In(1)
default:
return fmt.Errorf("subscriber %v takes wrong number of args: %v required signature %s", name, typ.NumIn(), subSig)
}
if !isExportedOrBuiltinType(argType) {
return fmt.Errorf("subscriber %v argument type not exported: %v", name, argType)
}
if typ.NumOut() != 1 {
return fmt.Errorf("subscriber %v has wrong number of outs: %v require signature %s",
name, typ.NumOut(), subSig)
}
if returnType := typ.Out(0); returnType != typeOfError {
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)View on GitHub (pinned to 24529f1404)
Solutions
- Export the message type (capitalize it, e.g. type Event struct) so it is visible outside its package.
- Use the generated protobuf message types (pb.XxxRequest/pb.XxxEvent) as the payload instead of local structs.
- If the type is in an internal/ package, move it to an importable exported package.
- If it must stay unexported, wrap it: declare an exported wrapper struct containing the payload.
Example fix
// before
func(ctx context.Context, e *eventPayload) error { ... } // unexported
// after
type EventPayload struct{ ... }
func(ctx context.Context, e *EventPayload) error { ... } Defensive patterns
Strategy: validation
Validate before calling
func exportedArg(fn interface{}) bool {
t := reflect.TypeOf(fn)
if t == nil || t.Kind() != reflect.Func || t.NumIn() != 2 { return false }
a := t.In(1)
if a.Kind() == reflect.Pointer { a = a.Elem() }
return a.PkgPath() == "" // empty PkgPath => builtin or exported
} Prevention
- Use exported (capitalized) message types, ideally generated protobuf types.
- Avoid internal/ packages for subscriber payload types.
- Wrap payloads in an exported struct if the underlying type must stay hidden.
- Check handler registration in a unit test that calls Subscribe during test setup.
When it happens
Trigger: Passing a subscriber func whose second parameter is an unexported type, e.g. func(ctx context.Context, e *myPrivateEvent) error where myPrivateEvent (or the package containing it) starts with a lowercase letter and lives outside the registering package.
Common situations: Defining message structs in an internal package or as unexported types next to the handler; accidentally using a lowercase type name for what should be a public proto-generated message; moving a handler into a shared package without exporting its payload type.
Related errors
- subscriber %v takes wrong number of args: %v required signat
- subscriber %v.%v takes wrong number of args: %v required sig
- %v argument type not exported: %v
- 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/22d7347e52be77dd.
Report an issue: GitHub.