{"record":{"id":"dea4577a06612fbe","repo":"vitessio/vitess","slug":"failed-to-parse-vtctld-host-address-template-s","errorCode":null,"errorMessage":"failed to parse vtctld host address template %s: %w","messagePattern":"failed to parse vtctld host address template (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtadmin/cluster/discovery/discovery_consul.go","lineNumber":161,"sourceCode":"\n\t/* vtctld options */\n\tif *vtctldDatacenterTmplStr != \"\" {\n\t\tdisco.vtctldDatacenter, err = generateConsulDatacenter(\"vtctld\", cluster, *vtctldDatacenterTmplStr)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to generate vtctld consul datacenter from template: %w\", err)\n\t\t}\n\t}\n\n\tif *vtctldFQDNTmplStr != \"\" {\n\t\tdisco.vtctldFQDNTmpl, err = template.New(\"consul-vtctld-fqdn-template-\" + cluster.Id).Parse(*vtctldFQDNTmplStr)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse vtctld FQDN template %s: %w\", *vtctldFQDNTmplStr, err)\n\t\t}\n\t}\n\n\tdisco.vtctldAddrTmpl, err = template.New(\"consul-vtctld-address-template-\" + cluster.Id).Parse(*vtctldAddrTmplStr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse vtctld host address template %s: %w\", *vtctldAddrTmplStr, err)\n\t}\n\n\treturn disco, nil\n}\n\nfunc generateConsulDatacenter(component string, cluster *vtadminpb.Cluster, tmplStr string) (string, error) {\n\ttmpl, err := template.New(\"consul-\" + component + \"-datacenter-\" + cluster.Id).Parse(tmplStr)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error parsing template %s: %w\", tmplStr, err)\n\t}\n\n\tdc, err := textutil.ExecuteTemplate(tmpl, &struct {\n\t\tCluster *vtadminpb.Cluster\n\t}{\n\t\tCluster: cluster,\n\t})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to execute template: %w\", err)","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtadmin/cluster/discovery/discovery_consul.go#L143-L179","documentation":"NewConsul always parses the vtctld address template (no empty-string guard). If template.Parse fails on the provided string, this error wraps the raw template and the underlying parse error, aborting construction of the consul discovery implementation.","triggerScenarios":"Calling NewConsul with a vtctld address template flag value that is not valid Go template syntax; this runs on every consul discovery instantiation whenever the string is supplied.","commonSituations":"Unbalanced {{ }}, shell interpolation stripping braces from env values, invalid functions or fields, mistakes when editing vtctld vs vtgate templates in tandem.","solutions":["Fix the vtctld address template syntax (e.g. \"{{ .Cluster.Id }}-vtctld:15000\").","Restrict template contents to fields on vtadminpb.Cluster.","Inspect the wrapped error message for the exact parse failure position.","Validate templates in CI by calling template.New(...).Parse on config values before deployment."],"exampleFix":"// before\nvtctld_address_template: \"{{ .Cluster.Id }-vtctld:15000\"\n// after\nvtctld_address_template: \"{{ .Cluster.Id }}-vtctld:15000\"","handlingStrategy":"validation","validationCode":"if _, err := template.New(\"check\").Parse(*vtctldAddrTmplStr); err != nil {\n    return fmt.Errorf(\"invalid vtctld address template: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"disco, err := NewConsul(cluster, args)\nif err != nil && strings.Contains(err.Error(), \"vtctld host address template\") {\n    log.Fatalf(\"fix vtctld address template: %v\", err)\n}","preventionTips":["The vtctld address template is required and parsed unconditionally — always validate it.","Keep templates as code constants where possible instead of free-form config.","Add an end-to-end config smoke test that constructs the consul discovery before deploy."],"tags":["go","template","consul","vtctld","address"],"backgroundTag":"template-parse-failed","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}