micro/go-micro · error

subscriber %v has wrong number of outs: %v require signature

Error message

subscriber %v has wrong number of outs: %v require signature %s

What it means

A subscriber function must return exactly one value: error (signature func(context.Context, interface{}) error). validateSubscriber rejects handlers whose return count differs from 1, because the dispatch code (createSubHandler) reads returnValues[0] unconditionally and needs an error to decide ack/retry behavior.

Source

Thrown at server/grpc/subscriber.go:131

}

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)
			default:
				return fmt.Errorf("subscriber %v.%v takes wrong number of args: %v required signature %s",
					name, method.Name, method.Type.NumIn(), subSig)

View on GitHub (pinned to 24529f1404)

Solutions

  1. Give the handler exactly one return value of type error.
  2. If you need to surface results, publish them on another topic or store them — subscribers communicate via errors only.
  3. If the handler can't fail, still return nil error: func(ctx context.Context, e *T) error { ...; return nil }.
  4. Move multi-value logic into an inner helper and wrap it in a signature-compliant subscriber.

Example fix

// before
srv.Subscribe("events", func(ctx context.Context, e *pb.Event) (bool, error) { ... })
// after
srv.Subscribe("events", func(ctx context.Context, e *pb.Event) error { ...; return nil })
Defensive patterns

Strategy: validation

Validate before calling

func singleErrorReturn(fn interface{}) bool {
	t := reflect.TypeOf(fn)
	return t != nil && t.Kind() == reflect.Func && t.NumOut() == 1 &&
		t.Out(0) == reflect.TypeOf((*error)(nil)).Elem()
}

Prevention

When it happens

Trigger: Registering a func with zero returns (func(ctx context.Context, e *T)) or multiple returns (func(ctx context.Context, e *T) (bool, error)), or a method-style subscriber method on a struct returning something other than exactly one error.

Common situations: Reusing an ordinary service method that returns (result, error) as a subscriber; stripping the error return to 'simplify' the handler; adapting a callback that logs instead of returning errors; converting handlers between frameworks with different conventions.

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/0d25bd841faeaf1b. Report an issue: GitHub.