vitessio/vitess · error

failed to execute template: %w

Error message

failed to execute template: %w

What it means

generateConsulDatacenter executes a successfully-parsed datacenter template against a struct containing the cluster proto via textutil.ExecuteTemplate. If execution fails (data mismatch, nil field access, invalid pipeline at render time), this error wraps the runtime failure. Unlike error 898 this is a template execution error, not a parse error.

Source

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

		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)
	}

	return dc, nil
}

// DiscoverVTGate is part of the Discovery interface.
func (c *ConsulDiscovery) DiscoverVTGate(ctx context.Context, tags []string) (*vtadminpb.VTGate, error) {
	span, ctx := trace.NewSpan(ctx, "ConsulDiscovery.DiscoverVTGate")
	defer span.Finish()

	executeFQDNTemplate := true

	return c.discoverVTGate(ctx, tags, executeFQDNTemplate)
}

// discoverVTGate calls discoverVTGates and then returns a random VTGate from
// the result. see discoverVTGates for further documentation.
func (c *ConsulDiscovery) discoverVTGate(ctx context.Context, tags []string, executeFQDNTemplate bool) (*vtadminpb.VTGate, error) {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Remove or guard field accesses that can be nil (wrap with {{ if .Cluster.SomeField }}...{{ end }}).
  2. Only use plain fields of vtadminpb.Cluster (Id, Names, etc.) rather than methods or deep pointer chains.
  3. Read the wrapped error, which names the exact template line where execution failed.
  4. Ensure the vtadminpb.Cluster passed to discovery.New is fully populated, not a zero-value proto.

Example fix

// before
--vtgate-datacenter-template="{{ .Cluster.ProxyTopology.Address }}" // panics if ProxyTopology nil
// after
--vtgate-datacenter-template="{{ .Cluster.Id }}"
Defensive patterns

Strategy: validation

Validate before calling

// execute a dry-run render before NewConsul
tmpl, err := template.New("dry").Parse(tmplStr)
if err == nil {
    var buf bytes.Buffer
    err = tmpl.Execute(&buf, struct{ Cluster *vtadminpb.Cluster }{Cluster: cluster})
}

Try / catch

disco, err := NewConsul(cluster, args)
if err != nil && strings.Contains(err.Error(), "failed to execute template") {
    log.Fatalf("template renders invalid data: %v", err)
}

Prevention

When it happens

Trigger: Calling NewConsul with a datacenter template that parses but fails during ExecuteTemplate — e.g. the template calls a method/field on a nil value or has a runtime-invalid pipeline given the vtadminpb.Cluster data.

Common situations: Templates guarded with {{ if }} on fields that are nil pointers in the Cluster proto, method calls not defined on proto types, cluster proto fields left unset in the request.

Related errors


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