Skip to content

panic: runtime error: comparing uncomparable type map[string]interface {} #19700

@cruvie

Description

@cruvie

Bug report criteria

What happened?

use grpc client made by etcd resolver with google.golang.org/grpc v1.71.0 cause panic

What did you expect to happen?

call rpc method successfully

How can we reproduce it (as minimally and precisely as possible)?

get a grpc client like this

import (
	"go.etcd.io/etcd/client/v3/naming/resolver"
	"google.golang.org/grpc"
)

// GetGrpcClient get grpc client for serverName
//
// don't forget to close conn conn.Close()
func GetGrpcClient[T any](serverName string,
	clientBuilder func(grpcConn grpc.ClientConnInterface) (client T),
	opts ...grpc.DialOption) (conn *grpc.ClientConn, client T, err error) {

	//refers to https://etcd.io/docs/v3.5/dev-guide/grpc_naming/
	etcdResolver, err := resolver.NewBuilder(GetClient())
	if err != nil {
		return nil, client, err
	}

	options := []grpc.DialOption{
		grpc.WithResolvers(etcdResolver),
		grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`),
	}
	options = append(options, opts...)

	conn, err = grpc.NewClient("etcd:///grpc/"+serverName,
		options...,
	)
	client = clientBuilder(conn)
	return conn, client, err
}

and use the client call a method

Anything else we need to know?

go 1.24
google.golang.org/grpc v1.70.0 works fine
create a grpc client manually works fine

func TestPanic(t *testing.T) {
	etcdCloseFunc := global_config.InitEtcdClient(false)
	defer etcdCloseFunc()
	_, client, err := GetClient()
	if err != nil {
		t.Error(err)
	} else {
		status, err := client.UpdateLocationOnlineStatus(context.Background(), &UpdateLocationOnlineStatus_Input{
			UserId: "test",
		})
		if err != nil {
			t.Error(err)
		}
		t.Log(status)
	}
}

func TestWorksFine(t *testing.T) {

	conn, err := grpc.NewClient("127.0.0.1:58759",
		grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()

	client := NewRPCDaZiNearbyClient(conn)
	ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2)
	defer cancelFunc()
	resp, err := client.UpdateLocationOnlineStatus(ctx, &UpdateLocationOnlineStatus_Input{
		UserId: "test",
	})
	if err != nil {
		log.Fatalf("could not test: %v", err)
	}
	log.Printf("DeleteTest response: %v", resp)
}

Etcd version (please run commands below)

deployed by docker

  ss-etcd:
    image: quay.io/coreos/etcd:v3.5.17-arm64
    # image: quay.io/coreos/etcd:v3.5.17-amd64
    container_name: ss-etcd
    command:
      [
        "/usr/local/bin/etcd",
        "--data-dir=/etcd-data",
        "--name=node1",
        "--initial-advertise-peer-urls=http://ss-etcd:2380",
        "--listen-peer-urls=http://0.0.0.0:2380",
        "--advertise-client-urls=http://ss-etcd:2379",
        "--listen-client-urls=http://0.0.0.0:2379",
        "--initial-cluster=node1=http://ss-etcd:2380"
      ]
    restart: unless-stopped
    ports:
      - "2379:2379"
      - "2380:2380"
    volumes:
      - ./etcd/data:/etcd-data

Etcd configuration (command line flags or environment variables)

default

Etcd debug information (please run commands below, feel free to obfuscate the IP address or FQDN in the output)

standalone

Relevant log output

=== RUN   TestPanic
panic: runtime error: comparing uncomparable type map[string]interface {}

goroutine 11 [running]:
google.golang.org/grpc/balancer/pickfirst/pickfirstleaf.equalAddressIgnoringBalAttributes(0x1400031c970, 0x1400031ca10)
	/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go:931 +0xe0
google.golang.org/grpc/balancer/pickfirst/pickfirstleaf.(*addressList).seekTo(0x14000333e20, {{0x14000040468, 0x13}, {0x0, 0x0}, 0x0, 0x140001225a0, {0x104f75a00, 0x14000414030}})
	/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go:905 +0xc8
google.golang.org/grpc/balancer/pickfirst/pickfirstleaf.(*pickfirstBalancer).updateSubConnState(0x14000333dd0, 0x1400030d880, {0x2, {0x0, 0x0}, {{0x14000040468, 0x13}, {0x14000152ea0, 0x21}, 0x0, ...}})
	/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go:627 +0x81c
google.golang.org/grpc/balancer/pickfirst/pickfirstleaf.(*pickfirstBalancer).newSCData.func1({0x2, {0x0, 0x0}, {{0x14000040468, 0x13}, {0x14000152ea0, 0x21}, 0x0, 0x140001225a0, {0x104f75a00, ...}}})
	/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go:197 +0x84
google.golang.org/grpc/internal/balancer/gracefulswitch.(*Balancer).updateSubConnState(0x140000f05a0, {0x105116900, 0x1400003ba40}, {0x2, {0x0, 0x0}, {{0x14000040468, 0x13}, {0x14000152ea0, 0x21}, ...}}, ...)
	/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/internal/balancer/gracefulswitch/gracefulswitch.go:262 +0x2bc
google.golang.org/grpc/internal/balancer/gracefulswitch.(*balancerWrapper).NewSubConn.func1({0x2, {0x0, 0x0}, {{0x14000040468, 0x13}, {0x14000152ea0, 0x21}, 0x0, 0x140001225a0, {0x104f75a00, ...}}})
	/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/internal/balancer/gracefulswitch/gracefulswitch.go:378 +0x98
google.golang.org/grpc.(*acBalancerWrapper).updateState.func1({0x105112108?, 0x140004f8c30?})
	/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/balancer_wrapper.go:341 +0x274
google.golang.org/grpc/internal/grpcsync.(*CallbackSerializer).run(0x14000111d80, {0x105112108, 0x140004f8c30})
	/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/internal/grpcsync/callback_serializer.go:94 +0x10c
created by google.golang.org/grpc/internal/grpcsync.NewCallbackSerializer in goroutine 25
	/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/internal/grpcsync/callback_serializer.go:52 +0x118

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions