{"record":{"id":"7ac9df03ec4f2ba5","repo":"grpc/grpc-go","slug":"name-resolver-error-v","errorCode":null,"errorMessage":"name resolver error: %v","messagePattern":"name resolver error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"balancer/pickfirst/pickfirst.go","lineNumber":234,"sourceCode":"\nfunc (b *pickfirstBalancer) resolverErrorLocked(err error) {\n\tif b.logger.V(2) {\n\t\tb.logger.Infof(\"Received error from the name resolver: %v\", err)\n\t}\n\n\t// The picker will not change since the balancer does not currently\n\t// report an error. If the balancer hasn't received a single good resolver\n\t// update yet, transition to TRANSIENT_FAILURE.\n\tif b.state != connectivity.TransientFailure && b.addressList.size() > 0 {\n\t\tif b.logger.V(2) {\n\t\t\tb.logger.Infof(\"Ignoring resolver error because balancer is using a previous good update.\")\n\t\t}\n\t\treturn\n\t}\n\n\tb.updateBalancerState(balancer.State{\n\t\tConnectivityState: connectivity.TransientFailure,\n\t\tPicker:            &picker{err: fmt.Errorf(\"name resolver error: %v\", err)},\n\t})\n}\n\nfunc (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState) error {\n\tb.mu.Lock()\n\tdefer b.mu.Unlock()\n\tb.cancelConnectionTimer()\n\tif len(state.ResolverState.Addresses) == 0 && len(state.ResolverState.Endpoints) == 0 {\n\t\t// Cleanup state pertaining to the previous resolver state.\n\t\t// Treat an empty address list like an error by calling b.ResolverError.\n\t\tb.closeSubConnsLocked()\n\t\tb.addressList.updateAddrs(nil)\n\t\tb.resolverErrorLocked(errors.New(\"produced zero addresses\"))\n\t\treturn balancer.ErrBadResolverState\n\t}\n\tb.healthCheckingEnabled = state.ResolverState.Attributes.Value(enableHealthListenerKeyType{}) != nil\n\tcfg, ok := state.BalancerConfig.(pfConfig)\n\tif state.BalancerConfig != nil && !ok {","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/balancer/pickfirst/pickfirst.go#L216-L252","documentation":"Produced by pickfirst's resolverErrorLocked (via ResolverError) when the name resolver errors AND the balancer has no good previous update to fall back on (empty address list or already in TransientFailure). The picker is replaced with one returning this error, so subsequent RPCs fail with Unavailable carrying the wrapped resolver error. This is the pickfirst equivalent of error 92.","triggerScenarios":"Using the default pick_first policy, the resolver returns an error (DNS failure, xDS NACK, or pickfirst itself flags an invalid update such as 'produced zero addresses') and there is no prior valid address list. resolverErrorLocked transitions to TransientFailure with this picker.","commonSituations":"Target DNS name doesn't exist or returns no records; xDS resource rejected by the client; target URI typo; resolver service (DNS, xDS server) unreachable; service not yet registered in discovery during a cold start.","solutions":["Read the wrapped %v — it is the underlying resolver error (DNS code, xDS NACK reason, etc.).","Confirm the target name resolves to addresses from the client host.","For xDS, verify the resource is accepted (no NACK) using channelz or client logs.","Add a client RetryPolicy so RPCs survive the transient resolver failure; for cold-start, gate on a readiness probe."],"exampleFix":"// before: non-existent service name\nconn, _ := grpc.NewClient(\"dns:///nonexistent-svc.default.svc.cluster.local:443\")\n// -> 'name resolver error: ... no such host'\n\n// after:\nconn, _ := grpc.NewClient(\"dns:///existing-svc.default.svc.cluster.local:443\")","handlingStrategy":"retry","validationCode":"// Pre-flight DNS for the pick_first target (same as error 92).\nfunc preflightResolve(target string) error { return checkResolves(target) }","typeGuard":null,"tryCatchPattern":"// pick_first surfaces resolver errors as codes.Unavailable; retry transient\n// failures and gate startup on readiness.\nfor i := 0; i < maxRetries; i++ {\n    err := stub.Do(ctx, req)\n    if err == nil { return nil }\n    if status.Code(err) != codes.Unavailable { return err }\n    select { case <-time.After(backoffFor(i)): case <-ctx.Done(): return ctx.Err() }\n}","preventionTips":["Pre-flight resolve the target before opening the channel.","Configure a RetryPolicy for codes.Unavailable on the channel.","For xDS-backed targets, confirm resources aren't NACKed (channelz).","Gate cold starts behind a readiness probe that waits for one READY SubConn."],"tags":["balancer","pickfirst","resolver","transient-failure","runtime","network"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}