thanos-io/thanos · error

could not load resolv.conf

Error message

could not load resolv.conf: %s

What it means

This error wraps a failure to read/parse the resolv.conf file before any DNS query is made. dns.ClientConfigFromFile could not open or parse the file at Resolver.ResolvConf, so lookupWithSearchPath aborts with the wrapped error including the underlying message.

Solutions

  1. Verify the resolv.conf path exists and is readable: ls -l /etc/resolv.conf (or your custom path) and cat it to check it parses
  2. Fix the resolv_conf_file path in your DNS SD discovery configuration to point at a valid file
  3. In containers, ensure the file is mounted (e.g. Kubernetes injects /etc/resolv.conf automatically; custom images must not delete it)
  4. Inspect the wrapped error text after 'could not load resolv.conf: ...' to distinguish open failure from parse failure

Example fix

// before
resolver, _ := miekgdns.NewResolver(30*time.Second, "nope", "/etc/missing-resolv.conf")
// after
resolver, _ := miekgdns.NewResolver(30*time.Second, "nope", "/etc/resolv.conf")
Defensive patterns

Strategy: validation

Validate before calling

if _, err := os.Stat(resolvConfPath); err != nil {
    return fmt.Errorf("resolv.conf %s unavailable: %w", resolvConfPath, err)
}

Try / catch

if _, err := r.LookupIPAddr(ctx, name); err != nil {
    if strings.Contains(err.Error(), "could not load resolv.conf") {
        return fmt.Errorf("DNS discovery misconfigured: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Constructing a Resolver with a ResolvConf path that does not exist, is unreadable (permissions), or contains malformed resolv.conf syntax, then calling any lookup method (lookupSRV, lookupIPAddr, lookupIPAddrByNetwork).

Common situations: Wrong custom resolv.conf path passed to the DNS SD config; file deleted in a container image; bind-mount missing in a container; corrupted or hand-edited resolv.conf with invalid directives.

Understand the failure class

Background: "Config file not found": what it means and how to fix it in docker-sync, Maven, Vagrant, Turborepo and other tools — this error's family across 60 libraries.

Related errors


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

Appendix: source

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

//     the servers in the "nameservers" list with the answer "that name does
//     not exist" (NXDOMAIN).  In that case, it can be considered
//     pseudo-authoritative that there are no records for that name.
//
//  3. One or more of the names was responded to by all servers with some
//     sort of error indication.  In that case, we can't know if, in fact,
//     there are records for the name or not, so whatever state the
//     configuration is in, we should keep it that way until we know for
//     sure (by, presumably, all the names getting answers in the future).
//
// Outcomes 1 and 2 are indicated by a valid response message (possibly an
// empty one) and no error.  Outcome 3 is indicated by an error return.  The
// error will be generic-looking, because trying to return all the errors
// returned by the combination of all name permutations and servers is a
// nightmare.
func (r *Resolver) lookupWithSearchPath(name string, qtype dns.Type) (*dns.Msg, error) {
	conf, err := dns.ClientConfigFromFile(r.ResolvConf)
	if err != nil {
		return nil, errors.Wrapf(err, "could not load resolv.conf: %s", err)
	}

	var errs []error
	for _, lname := range conf.NameList(name) {
		response, err := lookupFromAnyServer(lname, qtype, conf)
		if err != nil {
			// We can't go home yet, because a later name
			// may give us a valid, successful answer.  However
			// we can no longer say "this name definitely doesn't
			// exist", because we did not get that answer for
			// at least one name.
			errs = append(errs, err)
			continue
		}

		if response.Rcode == dns.RcodeSuccess {
			// Outcome 1: GOLD!
			return response, nil

View on GitHub (pinned to 35b8b99117)