thanos-io/thanos · error
exchange
Error message
exchange
What it means
Wraps any failure of dns.Client.Exchange — the actual network query to a DNS server. Everything from socket errors and timeouts to I/O failures during the request/response round-trip surfaces here with the original error attached.
Solutions
- Read the wrapped underlying error (e.g. 'i/o timeout', 'connection refused') to identify the transport problem
- Increase the Resolver timeout if slow resolvers are legitimately in use
- Verify UDP/TCP 53 connectivity to servAddr with dig @servAddr
- Fix routing/firewall/NAT issues between the client and the DNS server
Defensive patterns
Strategy: retry
Validate before calling
// sanity-check reachability and latency before lookups
t0 := time.Now(); err := probeDNS(server, name); if time.Since(t0) > timeout { /* resolver too slow */ } Try / catch
if err != nil && strings.Contains(err.Error(), "exchange") {
if errors.Is(err, context.DeadlineExceeded) || strings.Contains(err.Error(), "i/o timeout") {
return retryWithBackoff()
}
return err
} Prevention
- Set realistic DNS timeouts on the Resolver for your network conditions
- Test UDP/53 and TCP/53 reachability to each nameserver during deployment
- Watch for packet loss between clients and resolvers (network monitoring)
- Keep a fallback resolver (e.g. node-local or public DNS) in resolv.conf
When it happens
Trigger: client.Exchange(msg, servAddr) fails: UDP/TCP timeout (default or configured timeout exceeded), network unreachable, connection refused/reset, or short/invalid response read.
Common situations: DNS server down or overloaded; packet loss on the network; queries dropped by egress network policy; resolv.conf pointing at a non-DNS host; timeouts set too low for slow resolvers.
Related errors
- no such host
- could not resolve : all servers responded with errors to at…
- resolution against server
- unsupported network
- lookup IP addresses
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/aa2e08cc06ff6c2e.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/discovery/dns/miekgdns/lookup.go:140
}
return b.String()
}
// askServerForName makes a request to a specific DNS server for a specific
// name (and qtype). Retries with TCP in the event of response truncation,
// but otherwise just sends back whatever the server gave, whether that be a
// valid-looking response, or an error.
func askServerForName(name string, qType dns.Type, client *dns.Client, servAddr string, edns bool) (*dns.Msg, error) {
msg := &dns.Msg{}
msg.SetQuestion(dns.Fqdn(name), uint16(qType))
if edns {
msg.SetEdns0(dns.DefaultMsgSize, false)
}
response, _, err := client.Exchange(msg, servAddr)
if err != nil {
return nil, errors.Wrapf(err, "exchange")
}
if response.Truncated {
if client.Net == "tcp" {
return nil, errors.New("got truncated message on TCP (64kiB limit exceeded?)")
}
// TCP fallback.
client.Net = "tcp"
return askServerForName(name, qType, client, servAddr, false)
}
return response, nil
}
View on GitHub (pinned to 35b8b99117)