kubernetes/kops · error

error reading state store

Error message

error reading state store: %v

What it means

ClusterVFS.listNames enumerates clusters by reading the whole state-store tree via basePath.ReadTree. If reading the store fails (unreachable backend, bad credentials, missing store), the raw vfs error is wrapped in 'error reading state store'.

Solutions

  1. Verify the state store URL is correct and the bucket exists (aws s3 ls s3://<bucket>)
  2. Check cloud credentials/environment for the VFS backend
  3. Create the bucket or set KOPS_STATE_STORE correctly before listing
  4. If the store is legitimately empty, treat a not-found-style cause as an empty list
Defensive patterns

Strategy: fallback

Validate before calling

// verify state store before listing
if os.Getenv("KOPS_STATE_STORE") == "" && stateStoreURL == "" {
	return fmt.Errorf("KOPS_STATE_STORE must be set before listing clusters")
}

Try / catch

clusters, err := clusterVFS.List(ctx, metav1.ListOptions{})
if err != nil && strings.Contains(err.Error(), "error reading state store") {
	// check if store is simply empty/uninitialized
	if exists, _ := r.basePath.Exists(); !exists {
		return &api.ClusterList{}, nil
	}
	return fmt.Errorf("cannot reach state store %s: %w", basePath, err)
}

Prevention

When it happens

Trigger: Calling List (or anything calling listNames) when the state store path is wrong, the bucket does not exist, or the object store rejects the request.

Common situations: Typo in --state URL (e.g. s3://clusters vs s3://kops-clusters); region mismatch on the S3 bucket; credentials missing in CI; listing before any cluster was ever created and the prefix doesn't exist.

Related errors


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

Appendix: source

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

		c.SetGeneration(old.GetGeneration() + 1)
	}

	if err := r.writeConfig(ctx, c, r.basePath.Join(clusterName, registry.PathCluster), c, vfs.WriteOptionOnlyIfExists); err != nil {
		if os.IsNotExist(err) {
			return nil, err
		}
		return nil, fmt.Errorf("error writing Cluster: %v", err)
	}

	return c, nil
}

// List returns a slice containing all the cluster names
// It skips directories that don't look like clusters
func (r *ClusterVFS) listNames(ctx context.Context) ([]string, error) {
	paths, err := r.basePath.ReadTree(ctx)
	if err != nil {
		return nil, fmt.Errorf("error reading state store: %v", err)
	}

	var keys []string
	for _, p := range paths {
		relativePath, err := vfs.RelativePath(r.basePath, p)
		if err != nil {
			return nil, err
		}
		if !strings.HasSuffix(relativePath, "/config") {
			continue
		}
		key := strings.TrimSuffix(relativePath, "/config")
		keys = append(keys, key)
	}
	return keys, nil
}

func (r *ClusterVFS) find(ctx context.Context, clusterName string) (*api.Cluster, error) {

View on GitHub (pinned to 4c8573c808)