micro/go-micro · error

subscriber has wrong number of outs: 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.

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.

Appendix: 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)