vitessio/vitess · error

failed to parse vtgate host address template %s: %w

Error message

failed to parse vtgate host address template %s: %w

What it means

NewConsul always parses the vtgate address template (unlike the datacenter/FQDN options, there is no empty-string skip). If template.Parse fails, this error wraps the raw string and parse error. It means the vtgate address template cannot be compiled into a Go text/template.

Source

Thrown at go/vt/vtadmin/cluster/discovery/discovery_consul.go:141

	/* 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)
		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)

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Correct the vtgate address template so it parses as a valid Go text/template (e.g. "{{ .Cluster.Id }}.vtgate.example.com:15001").
  2. Use only fields present on vtadminpb.Cluster in the template body.
  3. Check the wrapped parse error for the exact character offset of the syntax problem.
  4. If config comes from env vars, verify the shell/YAML is not consuming braces or $ characters.

Example fix

// before
vtgate_address_template: "{{ .Cluster.Id }}:{ port" 
// after
vtgate_address_template: "{{ .Cluster.Id }}.vtgate:15001"
Defensive patterns

Strategy: validation

Validate before calling

if _, err := template.New("check").Parse(*vtgateAddrTmplStr); err != nil {
    return fmt.Errorf("invalid vtgate address template: %w", err)
}

Try / catch

disco, err := NewConsul(cluster, args)
if err != nil && strings.Contains(err.Error(), "vtgate host address template") {
    log.Fatalf("fix vtgate address template: %v", err)
}

Prevention

When it happens

Trigger: Calling NewConsul with a vtgate address template flag value containing invalid Go template syntax or unknown functions; this occurs unconditionally on every consul discovery construction, even if the address would not otherwise be used.

Common situations: Missing closing braces, shell expansion eating $ or { } in env var values, using a field not defined on vtadminpb.Cluster, single-vs-double quoting mistakes in YAML.

Understand the failure class

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/b69745b480dea5d3. Report an issue: GitHub.