hashicorp/nomad · error

unable to parse address template %q: %v

Error message

unable to parse address template %q: %v

What it means

Consul ApiConfig allows the consul address to be a Go text/template that renders to a single IP (e.g. to inject the advertise IP). If listenerutil.ParseSingleIPTemplate fails to render or the result is not a single IP, the config cannot build a consul API client and this error wraps the underlying cause.

Source

Thrown at nomad/structs/config/consul.go:344

		tID := *b.TaskIdentity
		result.TaskIdentity = &tID
	} else if b.TaskIdentity != nil {
		result.TaskIdentity = result.TaskIdentity.Merge(b.TaskIdentity)
	}

	return result
}

// ApiConfig returns a usable Consul config that can be passed directly to
// hashicorp/consul/api.  NOTE: datacenter is not set
func (c *ConsulConfig) ApiConfig() (*consul.Config, error) {
	// Get the default config from consul to reuse things like the default
	// http.Transport.
	config := consul.DefaultConfig()
	if c.Addr != "" {
		ipStr, err := listenerutil.ParseSingleIPTemplate(c.Addr)
		if err != nil {
			return nil, fmt.Errorf("unable to parse address template %q: %v", c.Addr, err)
		}
		config.Address = ipStr
	}
	if c.Token != "" {
		config.Token = c.Token
	}
	if c.Timeout != 0 {
		// Create a custom Client to set the timeout
		if config.HttpClient == nil {
			config.HttpClient = &http.Client{}
		}
		config.HttpClient.Timeout = c.Timeout
		config.HttpClient.Transport = config.Transport
	}
	if c.Auth != "" {
		var username, password string
		if strings.Contains(c.Auth, ":") {
			split := strings.SplitN(c.Auth, ":", 2)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Fix the template syntax in the consul addr to a valid function such as {{ GetPrivateIP }}
  2. Ensure the template resolves to exactly one IP on the agent
  3. Use a plain literal address like 127.0.0.1:8500 if no templating is needed

Example fix

// before
addr = "{{PrivateIP}}"
// after
addr = "{{ GetPrivateIP }}"
Defensive patterns

Strategy: validation

Validate before calling

addr := cfg.Consul.Addr
if strings.Contains(addr, "{{") {
    if _, err := listenerutil.ParseSingleIPTemplate(addr); err != nil {
        return fmt.Errorf("consul addr template invalid: %w", err)
    }
} else if net.ParseIP(strings.Split(addr, ":")[0]) == nil {
    return fmt.Errorf("consul addr %q is not a valid IP", addr)
}

Try / catch

cfg, err := consulCfg.ApiConfig()
if err != nil {
    return fmt.Errorf("building consul client: %w (check consul.addr template)", err)
}

Prevention

When it happens

Trigger: Calling ApiConfig() with a consul block whose addr contains a template like {{ GetPrivateIP }} that fails to parse/execute, or whose addr is otherwise not a valid single-IP expression.

Common situations: Template syntax typos ({{PrivateIP}} instead of {{ GetPrivateIP }}); template resolving to a hostname or multiple IPs; malformed literal addresses like '127.0.0.1:8500x'.

Understand the failure class

Related errors


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