hyperledger/fabric · error

receiver %T.%s does not return a an implementor of proto.Mes

Error message

receiver %T.%s does not return a an implementor of proto.Message as its first return value

What it means

Dispatch requires the first of the method's two return values to implement proto.Message (google.golang.org/protobuf), because it marshals that value into the response bytes. This error is thrown when the first return type does not implement proto.Message.

Source

Thrown at core/dispatcher/dispatcher.go:48

	if method == (reflect.Value{}) {
		return nil, errors.Errorf("receiver %T.%s does not exist", receiver, methodName)
	}

	if method.Type().NumIn() != 1 {
		return nil, errors.Errorf("receiver %T.%s has %d parameters but expected 1", receiver, methodName, method.Type().NumIn())
	}

	inputType := method.Type().In(0)
	if inputType.Kind() != reflect.Pointer {
		return nil, errors.Errorf("receiver %T.%s does not accept a pointer as its argument", receiver, methodName)
	}

	if method.Type().NumOut() != 2 {
		return nil, errors.Errorf("receiver %T.%s returns %d values but expected 2", receiver, methodName, method.Type().NumOut())
	}

	if !method.Type().Out(0).Implements(reflect.TypeFor[proto.Message]()) {
		return nil, errors.Errorf("receiver %T.%s does not return a an implementor of proto.Message as its first return value", receiver, methodName)
	}

	if !method.Type().Out(1).Implements(reflect.TypeFor[error]()) {
		return nil, errors.Errorf("receiver %T.%s does not return an error as its second return value", receiver, methodName)
	}

	inputValue := reflect.New(inputType.Elem())
	inputMsg, ok := inputValue.Interface().(proto.Message)
	if !ok {
		return nil, errors.Errorf("receiver %T.%s does not accept a proto.Message as its argument, it is '%T'", receiver, methodName, inputValue.Interface())
	}

	err := d.Protobuf.Unmarshal(inputBytes, inputMsg)
	if err != nil {
		return nil, errors.WithMessagef(err, "could not decode input arg for %T.%s", receiver, methodName)
	}

	outputVals := method.Call([]reflect.Value{inputValue})

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Change the first return value to a generated protobuf message type (*pb.SomeResponse).
  2. Regenerate proto types with the same protobuf-go module (google.golang.org/protobuf) the dispatcher uses; remove gogo/protobuf or golang/protobuf mixing.
  3. If a non-proto result is needed, serialize it into a field of a proto response wrapper message.

Example fix

// before
func (s *Svc) GetAsset(req *pb.GetRequest) (*Asset, error) { ... } // plain struct

// after
func (s *Svc) GetAsset(req *pb.GetRequest) (*pb.Asset, error) { ... } // generated proto type
Defensive patterns

Strategy: validation

Validate before calling

func validateFirstReturnIsProto(receiver any, methodName string) error {
    m := reflect.ValueOf(receiver).MethodByName(methodName)
    if !m.IsValid() || m.Type().NumOut() != 2 {
        return fmt.Errorf("method %s missing or wrong shape", methodName)
    }
    if !m.Type().Out(0).Implements(reflect.TypeFor[proto.Message]()) {
        return fmt.Errorf("method %s first return does not implement proto.Message", methodName)
    }
    return nil
}

Type guard

func firstReturnIsProtoMessage(receiver any, methodName string) bool {
    m := reflect.ValueOf(receiver).MethodByName(methodName)
    return m.IsValid() && m.Type().NumOut() >= 1 &&
        m.Type().Out(0).Implements(reflect.TypeFor[proto.Message]())
}

Prevention

When it happens

Trigger: Calling Dispatch (via Invoke) on a method whose first return is a plain struct, string, []byte, or other non-proto type, e.g. func (s *Svc) Do(req *pb.Req) (MyResult, error).

Common situations: Handlers returning application-defined structs instead of generated protobuf types; mixing gogo/protobuf or legacy golang/protobuf types with the google.golang.org/protobuf runtime the dispatcher imports, so Implements(proto.Message) fails across mismatched runtimes.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/b096ccc45792a2dc. Report an issue: GitHub.