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
- 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
- Fix the resolv_conf_file path in your DNS SD discovery configuration to point at a valid file
- In containers, ensure the file is mounted (e.g. Kubernetes injects /etc/resolv.conf automatically; custom images must not delete it)
- 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
- Stat/open the resolv.conf path at config-load time and fail fast
- In containers, never delete or override /etc/resolv.conf unless providing a valid replacement
- Use absolute paths for custom resolv.conf files and mount them explicitly in Kubernetes
- Parse-validate the file (dns.ClientConfigFromFile) in an init/health check
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
- missing port in address given for dnsdualstack lookup
- invalid lookup scheme
- raw resolution must be higher than the minimum block size…
- 5m resolution retention must be higher than the minimum…
- building gRPC client
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, nilView on GitHub (pinned to 35b8b99117)