hashicorp/nomad · error

Unable to parse address template %q: %v

Error message

Unable to parse address template %q: %v

What it means

parseMultipleIPTemplate renders a config value as a consul-template/go-sockaddr template expected to yield one or more space-separated IPs. If template.Parse fails (syntax error or evaluation failure), the error is wrapped as 'Unable to parse address template %q: %v'. It is used for multi-address fields such as addresses.http.

Source

Thrown at command/agent/config.go:2475

	// `template.Parse` returns a space-separated list of results, but on
	// Windows network interfaces are allowed to have spaces, so there is no
	// guaranteed separators that we can use to test if the template returned
	// multiple interfaces.
	// The test below checks if the template results to a single valid interface.
	_, err = net.InterfaceByName(out)
	if err != nil {
		return "", fmt.Errorf("invalid interface name %q", out)
	}

	return out, nil
}

// parseMultipleIPTemplate is used as a helper function to parse out a multiple IP
// addresses from a config parameter.
func parseMultipleIPTemplate(ipTmpl string) ([]string, error) {
	out, err := template.Parse(ipTmpl)
	if err != nil {
		return []string{}, fmt.Errorf("Unable to parse address template %q: %v", ipTmpl, err)
	}

	ips := strings.Split(out, " ")
	if len(ips) == 0 {
		return []string{}, errors.New("No addresses found, please configure one.")
	}

	return deduplicateAddrs(ips), nil
}

// normalizeAddrWithPort assumes that addr does not contain a port,
// noramlizes it per ipv6 RFC-5942 §4, and appends ":{port}".
func normalizeAddrWithPort(addr string, port int) string {
	return ipaddr.NormalizeAddr(net.JoinHostPort(addr, strconv.Itoa(port)))
}

// normalizeBind returns a normalized bind address.
//

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Fix the template syntax; ensure every {{ has a matching }}
  2. Validate the expression with a go-sockaddr evaluation (e.g. `consul anchor` style or unit test the filter)
  3. Check the wrapped %v message for the exact template failure
  4. Use a plain IP list instead of a template if dynamic discovery is not required

Example fix

// before
addresses { http = "{{ GetInterfaceIPs \"eth0\"" } # unclosed braces
// after
addresses { http = "{{ GetInterfaceIPs \"eth0\" }}" }
Defensive patterns

Strategy: validation

Validate before calling

func validMultiIPTemplate(tmpl string) error {
	if !strings.HasPrefix(tmpl, "{{") { return nil }
	if !strings.HasSuffix(tmpl, "}}") { return errors.New("unbalanced braces") }
	out, err := renderTemplate(tmpl)
	if err != nil { return err }
	for _, ip := range strings.Fields(out) {
		if net.ParseIP(ip) == nil { return fmt.Errorf("bad IP %q", ip) }
	}
	return nil
}

Prevention

When it happens

Trigger: Supplying a template string (e.g. in addresses.http) whose go-sockaddr/consul-template syntax is invalid: unclosed {{ }}, unknown function, or an expression that errors during evaluation.

Common situations: Copy-pasted templates with smart quotes or missing closing braces; unsupported go-sockaddr filter names; HCL escaping swallowing the braces; older agent versions lacking a newer template function.

Understand the failure class

Related errors


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