kubernetes/kops · error

%T is not a *compute.BackendService

Error message

%T is not a *compute.BackendService

What it means

A defensive type assertion in listHealthchecks: a Resource's Obj field was expected to be a *compute.BackendService but held a different type. This indicates an internal inconsistency — listBackendServices returned resources whose payloads are not regional backend services — rather than a user or API failure.

Source

Thrown at pkg/resources/gce/gce.go:1163

	}

	return bs, nil
}

func (d *clusterDiscoveryGCE) listHealthchecks() ([]*resources.Resource, error) {
	c := d.gceCloud
	// TODO: cache, for efficiency, if needed.
	// Find relevant healthchecks by finding all the backend services relevant to this
	// cluster, then selecting all the healthchecks they use.
	backendServices, err := d.listBackendServices()
	if err != nil {
		return nil, err
	}
	hcs := make(map[string]struct{})
	for _, bs := range backendServices {
		bsObj, ok := bs.Obj.(*compute.BackendService)
		if !ok {
			return nil, fmt.Errorf("%T is not a *compute.BackendService", bs)
		}
		for _, hc := range bsObj.HealthChecks {
			hcs[hc] = struct{}{}
		}
	}
	var hcResources []*resources.Resource
	for hc := range hcs {
		hcResources = append(hcResources, &resources.Resource{
			Name: gce.LastComponent(hc),
			ID:   gce.LastComponent(hc),
			Type: typeHealthcheck,
			Deleter: func(cloud fi.Cloud, r *resources.Resource) error {
				op, err := c.Compute().RegionHealthChecks().Delete(c.Project(), c.Region(), gce.LastComponent(hc))
				if err != nil {
					if gce.IsNotFound(err) {
						klog.Infof("Healthcheck not found, assuming deleted: %q", r.Name)
						return nil
					}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Confirm listBackendServices only inserts results from RegionBackendServices().List.
  2. Check the vendored gce cloud provider library version matches what kops expects (type may differ across versions).
  3. Extend the guard to log which resource produced the wrong type to speed diagnosis.
  4. This is an internal invariant violation — file/inspect kops code rather than changing cloud config.

Example fix

// before
bsObj, ok := bs.Obj.(*compute.BackendService)
if !ok {
	return nil, fmt.Errorf("%T is not a *compute.BackendService", bs)
}
// after
bsObj, ok := bs.Obj.(*compute.BackendService)
if !ok {
	return nil, fmt.Errorf("resource %q: %T is not a *compute.BackendService", bs.ID, bs.Obj)
}
Defensive patterns

Strategy: type-guard

Validate before calling

// verify the resource list source before consuming
if producedByRegionList(backendServices) == false {
	return fmt.Errorf("backend services list was not built from RegionBackendServices")
}

Type guard

func asBackendService(r *resources.Resource) (*compute.BackendService, bool) {
	bs, ok := r.Obj.(*compute.BackendService)
	return bs, ok
}

Try / catch

bsObj, ok := bs.Obj.(*compute.BackendService)
if !ok {
	klog.Warningf("skipping resource %q: %T is not a *compute.BackendService", bs.ID, bs.Obj)
	continue
}

Prevention

When it happens

Trigger: bs.Obj.(*compute.BackendService) fails because the resource tracker was populated with a different compute object type (e.g. a global backend service or a changed API type) — essentially only reachable if the resource list construction in listBackendServices drifts from this consumer's assumption.

Common situations: Mixing global vs regional backend service resources; a refactor or vendored cloud-library version change altering the concrete type stored in Resource.Obj; custom code reusing these list functions with other resource kinds.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/d81876196e45190f. Report an issue: GitHub.