thanos-io/thanos · error

could not resolve : no servers returned a viable answer…

Error message

could not resolve %s: no servers returned a viable answer. Errs %v

What it means

Returned when lookupFromAnyServer exhausted every configured DNS server without a viable answer: each server either errored (collected in errs) or returned a non-success/non-NXDOMAIN rcode such as SERVFAIL. lookupWithSearchPath then fails with this aggregate for the specific name being resolved.

Solutions

  1. Check the 'Errs' list at the end of the message for the per-server failure reasons
  2. Run dig +trace <name> to see where in the delegation chain resolution breaks
  3. Retry after confirming the authoritative zone for the name is healthy
  4. Switch to a known-good resolver (e.g. fix resolv.conf nameserver entries)
Defensive patterns

Strategy: retry

Validate before calling

// verify the name resolves via a reference resolver first
if err := probeDNS("8.8.8.8", name); err != nil { /* name itself is broken upstream */ }

Try / catch

addrs, err := r.LookupIPAddr(ctx, name)
if err != nil && strings.Contains(err.Error(), "no servers returned a viable answer") {
    // SERVFAIL-style transient: back off and retry
    time.Sleep(backoff); addrs, err = r.LookupIPAddr(ctx, name)
}

Prevention

When it happens

Trigger: All servers in conf.Servers fail to answer or return rcodes other than RcodeSuccess/RcodeNameError for the requested name and qtype (A/AAAA/SRV).

Common situations: Upstream DNS SERVFAIL due to broken zone delegation; recursive resolver unable to reach authoritative servers; rate limiting or response filtering by corporate DNS; DNSSEC validation failures.

Related errors


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/a4c19758d39844a2. Report an issue: GitHub.

Appendix: source

Thrown at pkg/discovery/dns/miekgdns/lookup.go:114

	client := &dns.Client{}

	var errs []error

	// TODO(bwplotka): Worth to do fanout and grab fastest as golang native lib?
	for _, server := range conf.Servers {
		servAddr := net.JoinHostPort(server, conf.Port)
		msg, err := askServerForName(name, qtype, client, servAddr, true)
		if err != nil {
			errs = append(errs, errors.Wrapf(err, "resolution against server %s for %s", server, name))
			continue
		}

		if msg.Rcode == dns.RcodeSuccess || msg.Rcode == dns.RcodeNameError {
			return msg, nil
		}
	}

	return nil, errors.Errorf("could not resolve %s: no servers returned a viable answer. Errs %v", name, fmtErrs(errs))
}

func fmtErrs(errs []error) string {
	b := bytes.Buffer{}
	for _, err := range errs {
		b.WriteString(";")
		b.WriteString(err.Error())
	}
	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{}

View on GitHub (pinned to 35b8b99117)