vitessio/vitess · error
failed to parse vtctld host address template
Error message
failed to parse vtctld host address template %s: %w
What it means
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.
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.
Example fix
// before
vtctld_address_template: "{{ .Cluster.Id }-vtctld:15000"
// after
vtctld_address_template: "{{ .Cluster.Id }}-vtctld:15000" Defensive patterns
Strategy: validation
Validate before calling
if _, err := template.New("check").Parse(*vtctldAddrTmplStr); err != nil {
return fmt.Errorf("invalid vtctld address template: %w", err)
} Try / catch
disco, err := NewConsul(cluster, args)
if err != nil && strings.Contains(err.Error(), "vtctld host address template") {
log.Fatalf("fix vtctld address template: %v", err)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Unbalanced {{ }}, shell interpolation stripping braces from env values, invalid functions or fields, mistakes when editing vtctld vs vtgate templates in tandem.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to execute vtctld address template for
- failed to execute vtctld fqdn template for
- failed to generate vtctld consul datacenter from template
- failed to parse vtctld FQDN template
- failed to parse vtgate host address template
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/dea4577a06612fbe.
Report an issue: GitHub.
Appendix: source
Thrown at go/vt/vtadmin/cluster/discovery/discovery_consul.go:161
/* vtctld options */
if *vtctldDatacenterTmplStr != "" {
disco.vtctldDatacenter, err = generateConsulDatacenter("vtctld", cluster, *vtctldDatacenterTmplStr)
if err != nil {
return nil, fmt.Errorf("failed to generate vtctld consul datacenter from template: %w", err)
}
}
if *vtctldFQDNTmplStr != "" {
disco.vtctldFQDNTmpl, err = template.New("consul-vtctld-fqdn-template-" + cluster.Id).Parse(*vtctldFQDNTmplStr)
if err != nil {
return nil, fmt.Errorf("failed to parse vtctld FQDN template %s: %w", *vtctldFQDNTmplStr, err)
}
}
disco.vtctldAddrTmpl, err = template.New("consul-vtctld-address-template-" + cluster.Id).Parse(*vtctldAddrTmplStr)
if err != nil {
return nil, fmt.Errorf("failed to parse vtctld host address template %s: %w", *vtctldAddrTmplStr, err)
}
return disco, nil
}
func generateConsulDatacenter(component string, cluster *vtadminpb.Cluster, tmplStr string) (string, error) {
tmpl, err := template.New("consul-" + component + "-datacenter-" + cluster.Id).Parse(tmplStr)
if err != nil {
return "", fmt.Errorf("error parsing template %s: %w", tmplStr, err)
}
dc, err := textutil.ExecuteTemplate(tmpl, &struct {
Cluster *vtadminpb.Cluster
}{
Cluster: cluster,
})
if err != nil {
return "", fmt.Errorf("failed to execute template: %w", err)View on GitHub (pinned to 01a25a7d17)