kubernetes/kops · error

ResourceVersion not supported in ClusterVFS::Get

Error message

ResourceVersion not supported in ClusterVFS::Get

What it means

ClusterVFS::Get is the VFS-backed implementation of the cluster store's Get. It does not support the ResourceVersion field of metav1.GetOptions, so any caller passing a non-empty ResourceVersion gets this error before any I/O happens. ResourceVersion semantics (watch/optimistic-concurrency reads) are a real API-server feature the VFS backend does not emulate.

Source

Thrown at pkg/client/simple/vfsclientset/cluster.go:52

	api "k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/apis/kops/registry"
	"k8s.io/kops/pkg/apis/kops/validation"
	"k8s.io/kops/util/pkg/vfs"
)

type ClusterVFS struct {
	VFSClientBase
}

func newClusterVFS(vfsContext *vfs.VFSContext, basePath vfs.Path) *ClusterVFS {
	c := &ClusterVFS{}
	c.Init("Cluster", vfsContext, basePath, StoreVersion)
	return c
}

func (c *ClusterVFS) Get(ctx context.Context, name string, options metav1.GetOptions) (*api.Cluster, error) {
	if options.ResourceVersion != "" {
		return nil, fmt.Errorf("ResourceVersion not supported in ClusterVFS::Get")
	}
	o, err := c.find(ctx, name)
	if err != nil {
		return nil, err
	}
	if o == nil {
		return nil, errors.NewNotFound(schema.GroupResource{Group: api.GroupName, Resource: "Cluster"}, name)
	}
	return o, nil
}

// Deprecated, but we need this for now..
func (c *ClusterVFS) configBase(clusterName string) (vfs.Path, error) {
	if clusterName == "" {
		return nil, fmt.Errorf("clusterName is required")
	}
	configPath := c.basePath.Join(clusterName)
	return configPath, nil

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Pass a zero-value metav1.GetOptions{} (no ResourceVersion) to ClusterVFS.Get
  2. Strip or reset options.ResourceVersion before calling Get when reusing options from another client
  3. If you need ResourceVersion semantics, use a real API-server clientset instead of the VFS store

Example fix

// before
o, err := clusterVFS.Get(ctx, "prod.example.com", metav1.GetOptions{ResourceVersion: "12345"})
// after
o, err := clusterVFS.Get(ctx, "prod.example.com", metav1.GetOptions{})
Defensive patterns

Strategy: validation

Validate before calling

if options.ResourceVersion != "" {
	return fmt.Errorf("vfs clientset does not support ResourceVersion in Get")
}
cluster, err := clusterVFS.Get(ctx, name, options)

Type guard

func getOptionsSafeForVFS(o metav1.GetOptions) bool {
	return o.ResourceVersion == ""
}

Try / catch

cluster, err := clusterVFS.Get(ctx, name, metav1.GetOptions{})
if err != nil {
	if strings.Contains(err.Error(), "ResourceVersion not supported") {
		// retry with zero-value options
		cluster, err = clusterVFS.Get(ctx, name, metav1.GetOptions{})
	}
	if err != nil {
		return err
	}
}

Prevention

When it happens

Trigger: Calling ClusterVFS.Get(ctx, name, metav1.GetOptions{ResourceVersion: "..."}) with any non-empty ResourceVersion string, e.g. copying GetOptions from a real clientset call or from generated client code.

Common situations: Code refactored from a kubernetes/client-go typed client to the simple VFS clientset; copied options structs that default-populate ResourceVersion; tests that set ResourceVersion to '0' or a real version string.

Related errors


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