kubernetes/kops · error

clientset bound to cluster %q, got cluster %q

Error message

clientset bound to cluster %q, got cluster %q

What it means

The controllerclientset client is bound to a single cluster (set at construction via c.clusterName); GetCluster rejects any requested name that differs. This is a strict name-mismatch guard so a misconfigured caller cannot silently read another cluster's config.

Source

Thrown at cmd/kops-controller/pkg/controllerclientset/clientset.go:58

		clusterName:     clusterName,

		clusterKeystore:    clusterKeystore,
		clusterSecretStore: clusterSecretStore,
	}, nil
}

type client struct {
	vfsContext         *vfs.VFSContext
	clusterBasePath    vfs.Path
	clusterName        string
	clusterKeystore    fi.CAStore
	clusterSecretStore fi.SecretStore
}

// GetCluster reads a cluster by name
func (c *client) GetCluster(ctx context.Context, name string) (*kops.Cluster, error) {
	if name != c.clusterName {
		return nil, fmt.Errorf("clientset bound to cluster %q, got cluster %q", c.clusterName, name)
	}

	p := c.clusterBasePath.Join("config")
	b, err := p.ReadFile(ctx)
	if err != nil {
		return nil, fmt.Errorf("reading file %v: %w", p, err)
	}

	gvk := kops.SchemeGroupVersion.WithKind("Cluster")
	object, _, err := kopscodecs.Decode(b, &gvk)
	if err != nil {
		return nil, fmt.Errorf("error parsing %v: %w", p, err)
	}

	cluster, ok := object.(*kops.Cluster)
	if !ok {
		return nil, fmt.Errorf("unexpected kind for cluster, got %T, want kops.Cluster", object)
	}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Use the exact bound cluster name (c.clusterName) in the request
  2. Construct the clientset with the cluster you intend to query
  3. Fix the --name/cluster flag passed to the calling command
  4. Refactor to a multi-cluster clientset if cross-cluster reads are required

Example fix

// before
cluster, err := clientset.GetCluster(ctx, "prod.example.com") // bound to dev.example.com
// after
cluster, err := clientset.GetCluster(ctx, "dev.example.com") // matches bound cluster
Defensive patterns

Strategy: validation

Validate before calling

// before calling GetCluster
if requestedName != boundClusterName {
	return fmt.Errorf("refusing GetCluster(%q): clientset bound to %q", requestedName, boundClusterName)
}

Type guard

func (c *client) canServe(name string) bool {
	return name == c.clusterName
}

Try / catch

cluster, err := clientset.GetCluster(ctx, name)
if err != nil {
	if strings.Contains(err.Error(), "bound to cluster") {
		return fmt.Errorf("wrong clientset for cluster %q", name)
	}
	return err
}

Prevention

When it happens

Trigger: Calling client.GetCluster(ctx, name) where name != c.clusterName — e.g. RunGetAll/RunGetClusters requesting multiple/other cluster names against a bound, single-cluster clientset.

Common situations: kops get operations iterating over several clusters while the controller clientset was created for one; stale CLI flag (--name) differing from the bound cluster; copy-pasted cluster name or typo.

Related errors


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