vitessio/vitess · error
failed to parse vtctld FQDN template %s: %w
Error message
failed to parse vtctld FQDN template %s: %w
What it means
NewConsul compiles the vtctld FQDN template with template.Parse; failure is wrapped with the raw template string and the parse error. This means the vtctld fully-qualified-domain-name template is not valid Go template syntax.
Source
Thrown at go/vt/vtadmin/cluster/discovery/discovery_consul.go:155
}
disco.vtgateAddrTmpl, err = template.New("consul-vtgate-address-template-" + cluster.Id).Parse(*vtgateAddrTmplStr)
if err != nil {
return nil, fmt.Errorf("failed to parse vtgate host address template %s: %w", *vtgateAddrTmplStr, err)
}
/* 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 {View on GitHub (pinned to 01a25a7d17)
Solutions
- Correct the template syntax so template.Parse succeeds.
- Mirror a known-good template, e.g. "{{ .Cluster.Id }}-vtctld.example.com".
- Empty the flag to skip the vtctld FQDN option entirely.
- Use the wrapped parse error to locate the bad token/offset.
Example fix
// before
vtctld_fqdn_template: "{{ .Cluster.Id }}-vtctld{{"
// after
vtctld_fqdn_template: "{{ .Cluster.Id }}-vtctld.example.com" Defensive patterns
Strategy: validation
Validate before calling
if s := *vtctldFQDNTmplStr; s != "" {
if _, err := template.New("check").Parse(s); err != nil {
return fmt.Errorf("invalid vtctld FQDN template %q: %w", s, err)
}
} Try / catch
disco, err := NewConsul(cluster, args)
if err != nil && strings.Contains(err.Error(), "vtctld FQDN template") {
log.Fatalf("fix vtctld FQDN template: %v", err)
} Prevention
- Use canonical examples: "{{ .Cluster.Id }}-vtctld.example.com".
- Run template.Parse in a startup validation step for every template flag.
- Avoid mixing vtgate and vtctld values in shared env vars.
When it happens
Trigger: Calling NewConsul (through discovery.New("consul", ...)) with a non-empty vtctld FQDN template flag containing syntax errors such as unbalanced braces, stray text/template operators, or calls to unregistered functions.
Common situations: Typo when duplicating the vtgate template for vtctld, quoting issues in YAML/env, referencing fields absent from vtadminpb.Cluster.
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 fqdn template for %v: %w
- failed to parse vtgate FQDN template %s: %w
- failed to generate vtctld consul datacenter from template: %
- failed to parse vtctld host address template %s: %w
- failed to execute vtgate fqdn template for %v: %w
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/5d149679c4cfef9c.
Report an issue: GitHub.