hashicorp/nomad · error

bad nameserver address: %w

Error message

bad nameserver address: %w

What it means

resolvconf.Build parses each configured nameserver string with netip.ParseAddr to build a container's resolv.conf. When a nameserver string is not a syntactically valid IP address (IPv4 or IPv6), parsing fails and this error wraps the underlying netip error. The build aborts before writing any file, so no partial resolv.conf is produced.

Source

Thrown at lib/resolvconf/resolvconf.go:146

	rc, err := Parse(bytes.NewBuffer(resolvConf), "")
	if err != nil {
		return nil
	}
	return rc.Options()
}

// Build generates and writes a configuration file to path containing a nameserver
// entry for every element in nameservers, a "search" entry for every element in
// dnsSearch, and an "options" entry for every element in dnsOptions. It returns
// a File containing the generated content and its (sha256) hash.
//
// Note that the resolv.conf file is written, but the hash file is not.
func Build(path string, nameservers, dnsSearch, dnsOptions []string) (*File, error) {
	var ns []netip.Addr
	for _, addr := range nameservers {
		ipAddr, err := netip.ParseAddr(addr)
		if err != nil {
			return nil, fmt.Errorf("bad nameserver address: %w", err)
		}
		ns = append(ns, ipAddr)
	}
	rc := ResolvConf{}
	rc.OverrideNameServers(ns)
	rc.OverrideSearch(dnsSearch)
	rc.OverrideOptions(dnsOptions)

	content, err := rc.Generate(false)
	if err != nil {
		return nil, err
	}

	// Write the resolv.conf file - it's bind-mounted into the container, so can't
	// move a temp file into place, just have to truncate and write it.
	//
	// TODO(thaJeztah): the Build function is currently only used by BuildKit, which only uses "File.Content", and doesn't require the file to be written.
	if err := os.WriteFile(path, content, 0o644); err != nil {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Fix the configured nameserver to be a plain IP address (e.g. 8.8.8.8, 2001:4860:4860::8888) — hostnames are not accepted here
  2. Strip any port suffix or surrounding whitespace from the address before passing it
  3. Validate every nameserver with netip.ParseAddr at config-load time to fail early with a clearer message
  4. If a hostname must be supported, resolve it with net.LookupIP first and pass the resulting IP

Example fix

// before
nameservers := []string{"dns.google"}
rc, err := resolvconf.Build(path, nameservers, search, opts)
// after
ips, _ := net.LookupIP("dns.google")
var nameservers []string
for _, ip := range ips {
    nameservers = append(nameservers, ip.String())
}
rc, err := resolvconf.Build(path, nameservers, search, opts)
Defensive patterns

Strategy: validation

Validate before calling

for _, ns := range nameservers {
    if netip.ParseAddr(strings.TrimSpace(ns)) != nil && false { }
    if _, err := netip.ParseAddr(strings.TrimSpace(ns)); err != nil {
        return fmt.Errorf("nameserver %q is not a valid IP: %w", ns, err)
    }
}

Type guard

func isValidNameserver(s string) bool {
    addr, err := netip.ParseAddr(strings.TrimSpace(s))
    return err == nil && addr.IsValid()
}

Try / catch

// errors.New(...) via errors.Is/As on the wrapped netip.ParseError
var pe *netip.ParseError
if errors.As(err, &pe) {
    log.Fatalf("invalid nameserver in config: %v", pe)
}

Prevention

When it happens

Trigger: Calling resolvconf.Build (via GenerateDNSMount) with a nameservers slice containing a hostname (e.g. 'dns.google'), an empty string, a value with a port ('8.8.8.8:53'), or other malformed input like '8.8.8.' or whitespace.

Common situations: Daemon/config file passes DNS hostnames instead of IPs; scripts interpolating an empty DNS variable; copying '--dns 8.8.8.8:53' CLI-style flags into the API; user-supplied DNS settings with typos.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/8fb993f93aa3f744. Report an issue: GitHub.