{"record":{"id":"c44d9749bb7cae82","repo":"hashicorp/nomad","slug":"unable-to-parse-address-template-q-v-c44d97","errorCode":null,"errorMessage":"unable to parse address template %q: %v","messagePattern":"unable to parse address template %q: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/config/consul.go","lineNumber":344,"sourceCode":"\t\ttID := *b.TaskIdentity\n\t\tresult.TaskIdentity = &tID\n\t} else if b.TaskIdentity != nil {\n\t\tresult.TaskIdentity = result.TaskIdentity.Merge(b.TaskIdentity)\n\t}\n\n\treturn result\n}\n\n// ApiConfig returns a usable Consul config that can be passed directly to\n// hashicorp/consul/api.  NOTE: datacenter is not set\nfunc (c *ConsulConfig) ApiConfig() (*consul.Config, error) {\n\t// Get the default config from consul to reuse things like the default\n\t// http.Transport.\n\tconfig := consul.DefaultConfig()\n\tif c.Addr != \"\" {\n\t\tipStr, err := listenerutil.ParseSingleIPTemplate(c.Addr)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to parse address template %q: %v\", c.Addr, err)\n\t\t}\n\t\tconfig.Address = ipStr\n\t}\n\tif c.Token != \"\" {\n\t\tconfig.Token = c.Token\n\t}\n\tif c.Timeout != 0 {\n\t\t// Create a custom Client to set the timeout\n\t\tif config.HttpClient == nil {\n\t\t\tconfig.HttpClient = &http.Client{}\n\t\t}\n\t\tconfig.HttpClient.Timeout = c.Timeout\n\t\tconfig.HttpClient.Transport = config.Transport\n\t}\n\tif c.Auth != \"\" {\n\t\tvar username, password string\n\t\tif strings.Contains(c.Auth, \":\") {\n\t\t\tsplit := strings.SplitN(c.Auth, \":\", 2)","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/config/consul.go#L326-L362","documentation":"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.","triggerScenarios":"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.","commonSituations":"Template syntax typos ({{PrivateIP}} instead of {{ GetPrivateIP }}); template resolving to a hostname or multiple IPs; malformed literal addresses like '127.0.0.1:8500x'.","solutions":["Fix the template syntax in the consul addr to a valid function such as {{ GetPrivateIP }}","Ensure the template resolves to exactly one IP on the agent","Use a plain literal address like 127.0.0.1:8500 if no templating is needed"],"exampleFix":"// before\naddr = \"{{PrivateIP}}\"\n// after\naddr = \"{{ GetPrivateIP }}\"","handlingStrategy":"validation","validationCode":"addr := cfg.Consul.Addr\nif strings.Contains(addr, \"{{\") {\n    if _, err := listenerutil.ParseSingleIPTemplate(addr); err != nil {\n        return fmt.Errorf(\"consul addr template invalid: %w\", err)\n    }\n} else if net.ParseIP(strings.Split(addr, \":\")[0]) == nil {\n    return fmt.Errorf(\"consul addr %q is not a valid IP\", addr)\n}","typeGuard":null,"tryCatchPattern":"cfg, err := consulCfg.ApiConfig()\nif err != nil {\n    return fmt.Errorf(\"building consul client: %w (check consul.addr template)\", err)\n}","preventionTips":["Test Go template expressions like {{ GetPrivateIP }} on the target host first","Prefer literal IP:port addresses unless templating is required","Ensure templates resolve to a single IP, not hostnames or ranges"],"tags":["config","consul","template","address"],"backgroundTag":"invalid-address-template","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}