grpc/grpc-go · warning
dns: record lookup error
Error message
dns: %v record lookup error: %v
What it means
handleDNSError (dns_resolver.go:278-291) inspects errors from LookupSRV/LookupTXT/LookupHost. Transient or timeout DNS errors are wrapped with this message and logged at Info level so gRPC can back off and retry; non-timeout, non-temporary failures (e.g. NXDOMAIN) are suppressed (returned as nil). The %v fields are the lookup type (SRV/TXT/A) and the underlying net.DNSError.
Solutions
- Verify the DNS server configured in /etc/resolv.conf (or container dnsPolicy) is reachable: nslookup <host> <server>.
- Increase the gRPC DNS resolution timeout (ResolvingTimeout) if the resolver is legitimately slow.
- Add retries / circuit-breaking at the caller; gRPC itself will back off, but upstream code should tolerate transient resolution failures.
- If running in Kubernetes, confirm dnsPolicy (ClusterFirst) and that the cluster-dns Service is healthy.
Example fix
// before: default resolution timeout too short for slow DNS // after: // import ( // dns "google.golang.org/grpc/internal/resolver/dns" // ) // // (configure via available options / environment as supported by your gRPC version) // // and ensure resolv.conf points to a reachable nameserver
Defensive patterns
Strategy: retry
Validate before calling
package main
import (
"context"
"net"
"time"
)
// Probe DNS reachability at startup so transient resolver problems surface
// before traffic flows.
func probeDNS(ctx context.Context, host string) error {
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
var r net.Resolver
_, err := r.LookupHost(ctx, host)
return err
}
// func main() { _ = probeDNS } Try / catch
// Transient DNS errors cause gRPC connection TRANSIENT_FAILURE with backoff;
// it will retry automatically. Surface it via connection-state watching.
//
// for {
// conn.WaitForStateChange(ctx, conn.GetState())
// if conn.GetState() == connectivity.Ready { break }
// } Prevention
- Point /etc/resolv.conf at a reliable, low-latency resolver.
- In Kubernetes, verify kube-dns/CoreDNS health and dnsPolicy.
- Tune ResolvingTimeout upward if your DNS is legitimately slow.
- Monitor DNS error rates and alert on sustained transient failures.
When it happens
Trigger: Triggered when a DNS lookup returns a *net.DNSError whose IsTimeout or IsTemporary is true, or when a non-DNSError is returned. The lookup type label ('A', 'SRV', 'TXT') indicates which resolution failed.
Common situations: DNS server unreachable, packet loss to the resolver, very slow DNS causing timeouts, a temporary network partition, /etc/resolv.conf pointing at an unreachable nameserver, or container DNS misconfiguration.
Related errors
- dns: error parsing A record IP address
- last resolver error
- delegating_resolver: invalid target address
- delegating_resolver: unable to build the proxy resolver
- dns resolver: missing address
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/6d0f00b5583a8c1d.
Report an issue: GitHub.
Appendix: source
Thrown at internal/resolver/dns/dns_resolver.go:287
return nil, fmt.Errorf("dns: error parsing A record IP address %v: %v", a, err)
}
addr := ip + ":" + strconv.Itoa(int(s.Port))
newAddrs = append(newAddrs, resolver.Address{Addr: addr, ServerName: s.Target})
}
}
return newAddrs, nil
}
func handleDNSError(err error, lookupType string) error {
dnsErr, ok := err.(*net.DNSError)
if ok && !dnsErr.IsTimeout && !dnsErr.IsTemporary {
// Timeouts and temporary errors should be communicated to gRPC to
// attempt another DNS query (with backoff). Other errors should be
// suppressed (they may represent the absence of a TXT record).
return nil
}
if err != nil {
err = fmt.Errorf("dns: %v record lookup error: %v", lookupType, err)
logger.Info(err)
}
return err
}
func (d *dnsResolver) lookupTXT(ctx context.Context) *serviceconfig.ParseResult {
ss, err := d.resolver.LookupTXT(ctx, txtPrefix+d.host)
if err != nil {
if envconfig.TXTErrIgnore {
return nil
}
if err = handleDNSError(err, "TXT"); err != nil {
return &serviceconfig.ParseResult{Err: err}
}
return nil
}
var res string
for _, s := range ss {View on GitHub (pinned to 0c51461d27)