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

  1. Fix the vtctld address template syntax (e.g. "{{ .Cluster.Id }}-vtctld:15000").
  2. Restrict template contents to fields on vtadminpb.Cluster.
  3. Inspect the wrapped error message for the exact parse failure position.
  4. 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

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

Related errors


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