vitessio/vitess · error
failed to parse vtctld host address template %s: %w
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.
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)
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 parse vtgate host address template %s: %w
- failed to generate vtctld consul datacenter from template: %
- failed to parse vtctld FQDN template %s: %w
- failed to execute vtctld address template for %v: %w
- failed to execute vtctld fqdn template for %v: %w
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/dea4577a06612fbe.
Report an issue: GitHub.