kubernetes/kops · error

expected slice, got %T

Error message

expected slice, got %T

What it means

readAll uses reflection and requires its items parameter to be a slice (pointer to a generated *<Kind>List type). Anything else fails this check. This is an internal contract violation by the caller of readAll (only List).

Source

Thrown at pkg/client/simple/vfsclientset/commonvfs.go:233

}

func (c *VFSClientBase) listNames(ctx context.Context) ([]string, error) {
	keys, err := listChildNames(ctx, c.basePath)
	if err != nil {
		return nil, fmt.Errorf("error listing %s in state store: %v", c.kind, err)
	}

	// Seems to be an assumption in k8s APIs that items are always returned sorted
	sort.Strings(keys)

	return keys, nil
}

func (c *VFSClientBase) readAll(ctx context.Context, items interface{}) (interface{}, error) {
	sliceValue := reflect.ValueOf(items)
	sliceType := reflect.TypeOf(items)
	if sliceType.Kind() != reflect.Slice {
		return nil, fmt.Errorf("expected slice, got %T", items)
	}

	names, err := c.listNames(ctx)
	if err != nil {
		return nil, err
	}

	for _, name := range names {
		o, err := c.Find(ctx, name)
		if err != nil {
			return nil, err
		}

		if o == nil {
			return nil, fmt.Errorf("%s was listed, but then not found %q", c.kind, name)
		}

		sliceValue = reflect.Append(sliceValue, reflect.ValueOf(o).Elem())

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Pass a pointer to the generated *<Kind>List type from the kops API (e.g. &kops.InstanceGroupList{}).
  2. Check the call site in List() to confirm the items argument type.
  3. Fix any custom/forked code that changed the argument type.

Example fix

// before
var out kops.InstanceGroup
items, err := c.readAll(ctx, &out)
// after
var out kops.InstanceGroupList
items, err := c.readAll(ctx, &out)
Defensive patterns

Strategy: type-guard

Validate before calling

func isListPointer(items interface{}) bool {
    t := reflect.TypeOf(items)
    return t != nil && t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct && strings.HasSuffix(t.Elem().Name(), "List")
}
if !isListPointer(items) { return fmt.Errorf("items must be *<Kind>List") }

Type guard

func isSlice(v interface{}) bool {
    return v != nil && reflect.TypeOf(v).Kind() == reflect.Ptr && reflect.TypeOf(v).Elem().Kind() == reflect.Slice
}

Try / catch

items, err := c.readAll(ctx, &kops.InstanceGroupList{})
if err != nil {
    if strings.Contains(err.Error(), "expected slice") {
        return fmt.Errorf("caller bug: items must be a *KindList pointer")
    }
    return err
}

Prevention

When it happens

Trigger: A caller passes a non-slice (e.g. a pointer to a single object like &kops.Cluster instead of &kops.ClusterList) into VFSClientBase.readAll via List.

Common situations: Custom/forked clientset code wiring List incorrectly; refactoring that changed the List item type; passing a single object where a List type is expected.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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