vitessio/vitess · error
failed to parse vtgate FQDN template %s: %w
Error message
failed to parse vtgate FQDN template %s: %w
What it means
During NewConsul, the vtgate FQDN template string is compiled with template.New(...).Parse. If parsing fails, the raw template string and underlying parse error are wrapped in this message. It indicates the vtgate fully-qualified-domain-name template is syntactically invalid Go template syntax.
Source
Thrown at go/vt/vtadmin/cluster/discovery/discovery_consul.go:135
"Optional Go template string to produce an FQDN to access the vtctld from a browser. "+
"E.g. \"{{ .Hostname }}.example.com\".")
if err := flags.Parse(args); err != nil {
return nil, err
}
/* gates options */
if *vtgateDatacenterTmplStr != "" {
disco.vtgateDatacenter, err = generateConsulDatacenter("vtgate", cluster, *vtgateDatacenterTmplStr)
if err != nil {
return nil, fmt.Errorf("failed to generate vtgate consul datacenter from template: %w", err)
}
}
if *vtgateFQDNTmplStr != "" {
disco.vtgateFQDNTmpl, err = template.New("consul-vtgate-fqdn-template-" + cluster.Id).Parse(*vtgateFQDNTmplStr)
if err != nil {
return nil, fmt.Errorf("failed to parse vtgate FQDN template %s: %w", *vtgateFQDNTmplStr, err)
}
}
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)View on GitHub (pinned to 01a25a7d17)
Solutions
- Fix the template syntax — ensure all {{ }} actions are closed and functions exist.
- Verify referenced fields exist on vtadminpb.Cluster (e.g. {{ .Cluster.Id }}).
- Empty the vtgate FQDN template flag to skip this option entirely.
- Check the wrapped parse error message, which includes the template parse position.
Example fix
// before
vtgate_fqdn_template: "{{ .Cluster.Id }-vtgate.example.com"
// after
vtgate_fqdn_template: "{{ .Cluster.Id }}-vtgate.example.com" Defensive patterns
Strategy: validation
Validate before calling
if s := *vtgateFQDNTmplStr; s != "" {
if _, err := template.New("check").Parse(s); err != nil {
return fmt.Errorf("invalid vtgate FQDN template %q: %w", s, err)
}
} Try / catch
disco, err := NewConsul(cluster, args)
if err != nil && strings.Contains(err.Error(), "vtgate FQDN template") {
log.Fatalf("fix vtgate FQDN template syntax: %v", err)
} Prevention
- Start from known-good examples like "{{ .Cluster.Id }}-vtgate.example.com".
- Validate templates in CI by parsing every non-empty template flag.
- Avoid shell interpolation that strips braces from env-provided templates.
When it happens
Trigger: Calling NewConsul (via discovery.New("consul", ...)) with a non-empty vtgate FQDN template flag containing invalid Go template syntax, e.g. "{{ .Cluster.Id" or an unknown pipeline function.
Common situations: Hand-edited YAML/env config with braces stripped or mangled by shell interpolation, copy-paste errors from docs, using fields not present on the Cluster proto.
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 generate vtgate consul datacenter from template: %
- 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 vtgate fqdn template for %v: %w
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/8feba8e272b4f218.
Report an issue: GitHub.