kubernetes/kops · error

error reading directory %q: %v

Error message

error reading directory %q: %v

What it means

VFSCAStore.ListKeysets reads the entire tree under <state-store>/<cluster>/private via vfs ReadTree to discover keysets. If the underlying storage (S3/GCS/etc.) read fails — permissions, missing bucket, network issues — the error is wrapped as "error reading directory" with the base path.

Source

Thrown at upup/pkg/fi/vfs_castore.go:165

	if !ok {
		klog.Fatalf("no YAML serializer registered")
	}
	encoder := codecs.EncoderForVersion(yaml.Serializer, v1alpha2.SchemeGroupVersion)

	if err := encoder.Encode(o, &objectData); err != nil {
		return nil, fmt.Errorf("error serializing keyset: %v", err)
	}
	return objectData.Bytes(), nil
}

// ListKeysets implements CAStore::ListKeysets
func (c *VFSCAStore) ListKeysets() (map[string]*Keyset, error) {
	ctx := context.TODO()

	baseDir := c.basedir.Join("private")
	files, err := baseDir.ReadTree(ctx)
	if err != nil {
		return nil, fmt.Errorf("error reading directory %q: %v", baseDir, err)
	}

	keysets := map[string]*Keyset{}

	for _, f := range files {
		relativePath, err := vfs.RelativePath(baseDir, f)
		if err != nil {
			return nil, err
		}

		tokens := strings.Split(relativePath, "/")
		if len(tokens) != 2 || tokens[1] != "keyset.yaml" {
			klog.V(2).Infof("ignoring unexpected file in keystore: %q", f)
			continue
		}

		name := tokens[0]
		loadedKeyset, err := c.loadKeyset(ctx, baseDir.Join(name))

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Verify KOPS_STATE_STORE/--state points to an existing, correctly-spelled bucket/path.
  2. Check cloud credentials and IAM permissions for listing/reading objects in the bucket.
  3. Confirm network access to the storage endpoint and correct region configuration.
  4. Run `kops get clusters` against the same state store to isolate whether the path or permissions are the problem.

Example fix

// before
export KOPS_STATE_STORE=s3://kops-state-backup  # bucket does not exist
// after
export KOPS_STATE_STORE=s3://my-kops-state  # existing bucket with read access
Defensive patterns

Strategy: retry

Validate before calling

// Verify the state store is readable before listing
ctx := context.TODO()
if _, err := vfs.Context.ReadLocation(os.Getenv("KOPS_STATE_STORE")).Join(cluster.Name).Join("config").ReadFile(ctx); err != nil {
	return fmt.Errorf("state store unreadable: %w", err)
}

Try / catch

keysets, err := store.ListKeysets()
if err != nil {
	if strings.Contains(err.Error(), "error reading directory") {
		// check creds/bucket, optionally retry with backoff
		return retryWithBackoff(func() error { _, e := store.ListKeysets(); return e })
	}
	return err
}

Prevention

When it happens

Trigger: Calling ListKeysets (or MirrorTo which uses related listing) when the state store path is inaccessible: bucket does not exist, credentials lack s3:ListBucket/GetObject, region mismatch, network outage, or the VFS path is misconfigured.

Common situations: Running `kops get secrets`/mirror commands with wrong --state or KOPS_STATE_STORE; IAM policies changed or creds expired; offline/blocked network access to the cloud storage endpoint; typo'd bucket name.

Related errors


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