vitessio/vitess · error

failed to generate vtctld consul datacenter from template: %

Error message

failed to generate vtctld consul datacenter from template: %w

What it means

Analogous to the vtgate case, NewConsul renders the optional vtctld datacenter template via generateConsulDatacenter and wraps any parse/execute failure with this message. It signals that the vtctld datacenter template string is invalid or cannot be rendered against the cluster proto.

Source

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

	}

	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)
	if err != nil {
		return nil, fmt.Errorf("failed to parse vtctld host address template %s: %w", *vtctldAddrTmplStr, err)
	}

	return disco, nil
}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Fix the vtctld datacenter template syntax to be a valid Go text/template.
  2. Reference only valid vtadminpb.Cluster fields (e.g. {{ .Cluster.Id }}).
  3. Leave the vtctld datacenter template empty to skip the feature — it is only parsed when non-empty.
  4. Read the wrapped inner error to distinguish parse vs execution failure.

Example fix

// before
--vtctld-datacenter-template="{{ if .Cluster.Id }}dc1"
// after
--vtctld-datacenter-template="{{ if .Cluster.Id }}dc1{{ end }}"
Defensive patterns

Strategy: validation

Validate before calling

if s := *vtctldDatacenterTmplStr; s != "" {
    if _, err := template.New("check").Parse(s); err != nil {
        return fmt.Errorf("invalid vtctld dc template: %w", err)
    }
}

Try / catch

disco, err := NewConsul(cluster, args)
if err != nil && strings.Contains(err.Error(), "vtctld consul datacenter") {
    log.Fatalf("bad vtctld datacenter template: %v", err)
}

Prevention

When it happens

Trigger: Passing a non-empty vtctld-datacenter-template flag whose Go template fails to parse (syntax error) or whose execution against &struct{Cluster *vtadminpb.Cluster} fails, during NewConsul.

Common situations: Invalid template syntax from manual edits, referencing nonexistent Cluster fields, environment/config tooling mangling braces, copy-paste between vtgate and vtctld flags introducing a typo.

Related errors


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