grpc/grpc-go · warning
name resolver error: %v
Error message
name resolver error: %v
What it means
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.
Source
Thrown at balancer/pickfirst/pickfirst.go:234
func (b *pickfirstBalancer) resolverErrorLocked(err error) {
if b.logger.V(2) {
b.logger.Infof("Received error from the name resolver: %v", err)
}
// The picker will not change since the balancer does not currently
// report an error. If the balancer hasn't received a single good resolver
// update yet, transition to TRANSIENT_FAILURE.
if b.state != connectivity.TransientFailure && b.addressList.size() > 0 {
if b.logger.V(2) {
b.logger.Infof("Ignoring resolver error because balancer is using a previous good update.")
}
return
}
b.updateBalancerState(balancer.State{
ConnectivityState: connectivity.TransientFailure,
Picker: &picker{err: fmt.Errorf("name resolver error: %v", err)},
})
}
func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState) error {
b.mu.Lock()
defer b.mu.Unlock()
b.cancelConnectionTimer()
if len(state.ResolverState.Addresses) == 0 && len(state.ResolverState.Endpoints) == 0 {
// Cleanup state pertaining to the previous resolver state.
// Treat an empty address list like an error by calling b.ResolverError.
b.closeSubConnsLocked()
b.addressList.updateAddrs(nil)
b.resolverErrorLocked(errors.New("produced zero addresses"))
return balancer.ErrBadResolverState
}
b.healthCheckingEnabled = state.ResolverState.Attributes.Value(enableHealthListenerKeyType{}) != nil
cfg, ok := state.BalancerConfig.(pfConfig)
if state.BalancerConfig != nil && !ok {View on GitHub (pinned to 03255a9237)
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.
Example fix
// before: non-existent service name
conn, _ := grpc.NewClient("dns:///nonexistent-svc.default.svc.cluster.local:443")
// -> 'name resolver error: ... no such host'
// after:
conn, _ := grpc.NewClient("dns:///existing-svc.default.svc.cluster.local:443") Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight DNS for the pick_first target (same as error 92).
func preflightResolve(target string) error { return checkResolves(target) } Try / catch
// pick_first surfaces resolver errors as codes.Unavailable; retry transient
// failures and gate startup on readiness.
for i := 0; i < maxRetries; i++ {
err := stub.Do(ctx, req)
if err == nil { return nil }
if status.Code(err) != codes.Unavailable { return err }
select { case <-time.After(backoffFor(i)): case <-ctx.Done(): return ctx.Err() }
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- last resolver error: %v
- last connection error: %v; last resolver error: %v
- last connection error: %v
- all SubConns are in TransientFailure, last connection error:
- all SubConns are in TransientFailure
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/7ac9df03ec4f2ba5.
Report an issue: GitHub.