Search code examples
gogrpc

Type cannot implement 'X' as it has a non-exported method and is defined in a different package


I have this code:

s := grpc.NewServer()
pb.RegisterMessageServiceServer(s, &messageServer{})

I have this error:

Cannot use '&messageServer{}' (type *messageServer) as the type MessageServiceServer Type cannot implement 'MessageServiceServer' as it has a non-exported method and is defined in a different package

My messageServer struct looks like:

type messageServer struct{}

func (s *messageServer) mustEmbedUnimplementedMessageServiceServer() {
    //TODO implement me
    panic("implement me")
}

func (s *messageServer) MustEmbedUnimplementedMessageServiceServer() {
    //TODO implement me
    panic("implement me")
}

func (s *messageServer) SendMessage(ctx context.Context, msg *pb.Message) (*pb.Response, error) {
    // Write the message to Kafka
    producer, err := sarama.NewSyncProducer([]string{kafkaBroker}, nil)
    if err != nil {
        log.Fatalf("Error creating Kafka producer: %v", err)
        return nil, err
    }
    defer producer.Close()

    kafkaMsg := &sarama.ProducerMessage{
        Topic: kafkaTopic,
        Value: sarama.StringEncoder(msg.Content),
    }

    _, _, err = producer.SendMessage(kafkaMsg)
    if err != nil {
        log.Printf("Failed to send message to Kafka: %v", err)
        return nil, err
    }

    return &pb.Response{Message: "Message sent to Kafka"}, nil
}

the error is on this line:

pb.RegisterMessageServiceServer(s, &messageServer{}) // here

no idea what's happening :(


Solution

  • You're not supposed to provide an implementation of mustEmbedUnimplementedMessageServiceServer(). You're supposed to make your server struct embed UnimplementedMessageServiceServer. The member is named that to tell you that. The interface also has a doc comment that says

    All implementations must embed UnimplementedMessageServiceServer for forward compatibility.

    The idea is that some day, the gRPC devs might add a new method to the interface for servers. If they do, they will also add a new method to the unimplemented types that returns a "method Blah not implemented" error. Since you're forced to embed their unimplemented type in your server type, you will inherit that method, and get a default implementation that throws an error, instead of having your code suddenly start failing typechecks because your server type is missing the new method.