diff --git a/clientconn.go b/clientconn.go index cfc204c2fe3..e5c31208f1d 100644 --- a/clientconn.go +++ b/clientconn.go @@ -591,9 +591,16 @@ func (cc *ClientConn) updateResolverState(s resolver.State, err error) error { } else { ret = balancer.ErrBadResolverState if cc.balancerWrapper == nil { - cc.blockingpicker.updatePicker(base.NewErrPicker(status.Errorf(codes.Unavailable, "error parsing service config: %v", s.ServiceConfig.Err))) + var err error + if s.ServiceConfig.Err != nil { + err = status.Errorf(codes.Unavailable, "error parsing service config: %v", s.ServiceConfig.Err) + } else { + err = status.Errorf(codes.Unavailable, "illegal service config type: %T", s.ServiceConfig.Config) + } + cc.blockingpicker.updatePicker(base.NewErrPicker(err)) cc.csMgr.updateState(connectivity.TransientFailure) cc.mu.Unlock() + cc.firstResolveEvent.Fire() return ret } } diff --git a/resolver_conn_wrapper_test.go b/resolver_conn_wrapper_test.go index 4127d644784..60e7d0d7ad8 100644 --- a/resolver_conn_wrapper_test.go +++ b/resolver_conn_wrapper_test.go @@ -19,14 +19,18 @@ package grpc import ( + "context" "errors" "fmt" "net" + "strings" "testing" "time" + "google.golang.org/grpc/codes" "google.golang.org/grpc/resolver" "google.golang.org/grpc/resolver/manual" + "google.golang.org/grpc/status" ) func (s) TestParseTarget(t *testing.T) { @@ -197,3 +201,25 @@ func (s) TestServiceConfigErrorPolling(t *testing.T) { go r.CC.UpdateState(resolver.State{}) }) } + +func (s) TestServiceConfigErrorRPC(t *testing.T) { + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + + cc, err := Dial(r.Scheme()+":///test.server", WithInsecure()) + if err != nil { + t.Fatalf("Dial(_, _) = _, %v; want _, nil", err) + } + defer cc.Close() + badsc := r.CC.ParseServiceConfig("bad config") + r.UpdateState(resolver.State{ServiceConfig: badsc}) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + var dummy int + const wantMsg = "error parsing service config" + const wantCode = codes.Unavailable + if err := cc.Invoke(ctx, "/foo/bar", &dummy, &dummy); status.Code(err) != wantCode || !strings.Contains(status.Convert(err).Message(), wantMsg) { + t.Fatalf("cc.Invoke(_, _, _, _) = %v; want status.Code()==%v, status.Message() contains %q", err, wantCode, wantMsg) + } +}